From aebf6678a8ea81ef48ac24c0a259130d9ab9e42e Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 7 Jul 2021 16:54:14 -0400 Subject: [PATCH 001/895] wip: move out of dioxus main --- .gitignore | 2 + .vscode/settings.json | 3 + Cargo.toml | 33 ++++++++++ README.md | 48 ++++++++++++++ src/builder.rs | 146 ++++++++++++++++++++++++++++++++++++++++++ src/cargo.rs | 69 ++++++++++++++++++++ src/cli.rs | 62 ++++++++++++++++++ src/config.rs | 92 ++++++++++++++++++++++++++ src/develop.rs | 111 ++++++++++++++++++++++++++++++++ src/error.rs | 34 ++++++++++ src/lib.rs | 8 +++ src/logging.rs | 49 ++++++++++++++ src/main.rs | 28 ++++++++ src/watch.rs | 11 ++++ 14 files changed, 696 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/builder.rs create mode 100644 src/cargo.rs create mode 100644 src/cli.rs create mode 100644 src/config.rs create mode 100644 src/develop.rs create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/logging.rs create mode 100644 src/main.rs create mode 100644 src/watch.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..96ef6c0b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..80f51cff8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.inlayHints.enable": false +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..299a26ae6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "dioxus-studio" +version = "0.1.0" +authors = ["Jonathan Kelley "] +edition = "2018" +description = "CLI tool for developing, testing, and publishing Dioxus apps" +"license" = "MIT/Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +thiserror = "1.0.23" +log = "0.4.13" +fern = { version="0.6.0", features=["colored"] } +wasm-bindgen-cli-support = "0.2.73" +anyhow = "1.0.38" +argh = "0.1.4" +serde = "1.0.120" +serde_json = "1.0.61" +async-std = { version="1.9.0", features=["attributes"] } +tide = "0.15.0" +fs_extra = "1.2.0" + +cargo_toml = "0.8.1" +futures = "0.3.12" +notify = "5.0.0-pre.4" +rjdebounce = "0.2.1" +tempfile = "3.2.0" + +[[bin]] + +path = "src/main.rs" +name = "dioxus" diff --git a/README.md b/README.md new file mode 100644 index 000000000..bf2e3310a --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +
+

📦✨ dioxus-cli

+

+ Tooling to supercharge dioxus projects +

+
+ +# About +--- +dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development just a simple two commands: `cargo init` and `dioxus-cli publish`. + +Best thing: +- No NPM. +- No Webpack. +- No `node_modules`. +- No Babel +- No parcel +- No rollup +- No ESLint + +Just install Rust, dioxus-cli, and you're good to go. +`cargo install --git github.com/jkelleyrtp/dioxus-cli` + +Need a development server? +`dioxus develop` + +Need to run an example? +`dioxus develop --example textbox` + +Need to benchmark a component? +`dioxus bench` + +Need to test your code? +`dioxus test` + +Need to build your code into a bundle? +`dioxus build --outdir public` + +Need to publish your code to GitHub pages, Netlify, etc? +`dioxus publish --ghpages myrepo.git` + +# Use in your project +--- +Sometimes you'll want to include static assets without bundling them into your .wasm content. dioxus-cli provides a few ways of doing this: + +- Load in dynamic content using `dioxus::asset("./static/images/blah.svg")` +- Live-reload HTML templates without rebuilding your .wasm with `dioxus::template("./templates/blah.html")` +- Use a CSS library like tailwind in your dioxus configuration with diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 000000000..1d06b3ae8 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,146 @@ +use crate::{ + cli::BuildOptions, + config::{Config, ExecutableType}, + error::Result, +}; +use log::{info, warn}; +use std::{io::Write, process::Command}; +use wasm_bindgen_cli_support::Bindgen; + +pub struct BuildConfig {} +impl Into for BuildOptions { + fn into(self) -> BuildConfig { + BuildConfig {} + } +} +impl Default for BuildConfig { + fn default() -> Self { + Self {} + } +} + +pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> { + /* + [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) + [2] Generate the appropriate build folders + [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm + [4] Wasm-opt the .wasm file with whatever optimizations need to be done + [5] Link up the html page to the wasm module + */ + + let Config { + out_dir, + crate_dir, + target_dir, + static_dir, + executable, + .. + } = config; + + let t_start = std::time::Instant::now(); + + // [1] Build the .wasm module + info!("Running build commands..."); + let mut cmd = Command::new("cargo"); + cmd.current_dir(&crate_dir) + .arg("build") + .arg("--target") + .arg("wasm32-unknown-unknown") + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()); + + if config.release { + cmd.arg("--release"); + } + + match executable { + ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), + ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), + ExecutableType::Example(name) => cmd.arg("--example").arg(name), + }; + + let mut child = cmd.spawn()?; + let _err_code = child.wait()?; + + info!("Build complete!"); + + // [2] Establish the output directory structure + let bindgen_outdir = out_dir.join("wasm"); + + // [3] Bindgen the final binary for use easy linking + let mut bindgen_builder = Bindgen::new(); + + let release_type = match config.release { + true => "release", + false => "debug", + }; + + let input_path = match executable { + ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir + // .join("wasm32-unknown-unknown/release") + .join(format!("wasm32-unknown-unknown/{}", release_type)) + .join(format!("{}.wasm", name)), + + ExecutableType::Example(name) => target_dir + // .join("wasm32-unknown-unknown/release/examples") + .join(format!("wasm32-unknown-unknown/{}/examples", release_type)) + .join(format!("{}.wasm", name)), + }; + + bindgen_builder + .input_path(input_path) + .web(true)? + .debug(true) + .demangle(true) + .keep_debug(true) + .remove_name_section(false) + .remove_producers_section(false) + .out_name("module") + .generate(&bindgen_outdir)?; + + // [4] + // TODO: wasm-opt + + // [5] Generate the html file with the module name + // TODO: support names via options + info!("Writing to '{:#?}' directory...", out_dir); + let mut file = std::fs::File::create(out_dir.join("index.html"))?; + file.write_all(gen_page("./wasm/module.js").as_str().as_bytes())?; + + let copy_options = fs_extra::dir::CopyOptions::new(); + match fs_extra::dir::copy(static_dir, out_dir, ©_options) { + Ok(_) => {} + Err(_e) => { + warn!("Error copying dir"); + } + } + + let t_end = std::time::Instant::now(); + log::info!("Done in {}ms! 🎉", (t_end - t_start).as_millis()); + Ok(()) +} + +fn gen_page(module: &str) -> String { + format!( + r#" + + + + + + + + + + + +"#, + module + ) +} diff --git a/src/cargo.rs b/src/cargo.rs new file mode 100644 index 000000000..3a911a81e --- /dev/null +++ b/src/cargo.rs @@ -0,0 +1,69 @@ +//! Utilities for working with cargo and rust files +use crate::error::{Error, Result}; +use std::{env, fs, path::PathBuf, process::Command, str}; + +/// How many parent folders are searched for a `Cargo.toml` +const MAX_ANCESTORS: u32 = 10; + +/// Returns the root of the crate that the command is run from +/// +/// If the command is run from the workspace root, this will return the top-level Cargo.toml +pub fn crate_root() -> Result { + // From the current directory we work our way up, looking for `Cargo.toml` + env::current_dir() + .ok() + .and_then(|mut wd| { + for _ in 0..MAX_ANCESTORS { + if contains_manifest(&wd) { + return Some(wd); + } + if !wd.pop() { + break; + } + } + None + }) + .ok_or_else(|| Error::CargoError("Failed to find the cargo directory".to_string())) +} + +/// Returns the root of a workspace +/// TODO @Jon, find a different way that doesn't rely on the cargo metadata command (it's slow) +pub fn workspace_root() -> Result { + let output = Command::new("cargo") + .args(&["metadata"]) + .output() + .map_err(|_| Error::CargoError("Manifset".to_string()))?; + + if !output.status.success() { + let mut msg = str::from_utf8(&output.stderr).unwrap().trim(); + if msg.starts_with("error: ") { + msg = &msg[7..]; + } + + return Err(Error::CargoError(msg.to_string())); + } + + let stdout = str::from_utf8(&output.stdout).unwrap(); + for line in stdout.lines() { + let meta: serde_json::Value = serde_json::from_str(line) + .map_err(|_| Error::CargoError("InvalidOutput".to_string()))?; + + let root = meta["workspace_root"] + .as_str() + .ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))?; + return Ok(root.into()); + } + + Err(Error::CargoError("InvalidOutput".to_string())) +} + +/// Checks if the directory contains `Cargo.toml` +fn contains_manifest(path: &PathBuf) -> bool { + fs::read_dir(path) + .map(|entries| { + entries + .filter_map(Result::ok) + .any(|ent| &ent.file_name() == "Cargo.toml") + }) + .unwrap_or(false) +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 000000000..852d4ee71 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,62 @@ +use argh::FromArgs; + +#[derive(FromArgs, PartialEq, Debug)] +/// Top-level command. +pub struct LaunchOptions { + #[argh(subcommand)] + pub command: LaunchCommand, +} + +/// The various kinds of commands that `wasm-pack` can execute. +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +pub enum LaunchCommand { + Develop(DevelopOptions), + Build(BuildOptions), + Test(TestOptions), + Publish(PublishOptions), +} + +/// Publish your yew application to Github Pages, Netlify, or S3 +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "publish")] +pub struct PublishOptions {} + +/// 🔬 test your yew application! +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "test")] +pub struct TestOptions { + /// an example in the crate + #[argh(option)] + pub example: Option, +} + +/// 🏗️ Build your yew application +#[derive(FromArgs, PartialEq, Debug, Clone)] +#[argh(subcommand, name = "build")] +pub struct BuildOptions { + /// an optional direction which is "up" by default + #[argh(option, short = 'o', default = "String::from(\"public\")")] + pub outdir: String, + + /// an example in the crate + #[argh(option)] + pub example: Option, + + /// develop in release mode + #[argh(switch, short = 'r')] + pub release: bool, +} + +/// 🛠 Start a development server +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "develop")] +pub struct DevelopOptions { + /// an example in the crate + #[argh(option)] + pub example: Option, + + /// develop in release mode + #[argh(switch, short = 'r')] + pub release: bool, +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 000000000..02a04eaf7 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,92 @@ +use crate::{ + cli::{BuildOptions, DevelopOptions}, + error::Result, +}; +use std::{io::Write, path::PathBuf, process::Command}; + +#[derive(Debug, Clone)] +pub struct Config { + pub out_dir: PathBuf, + pub crate_dir: PathBuf, + pub workspace_dir: PathBuf, + pub target_dir: PathBuf, + pub static_dir: PathBuf, + pub manifest: cargo_toml::Manifest, + pub executable: ExecutableType, + pub release: bool, +} + +#[derive(Debug, Clone)] +pub enum ExecutableType { + Binary(String), + Lib(String), + Example(String), +} + +impl Config { + pub fn new() -> Result { + let crate_dir = crate::cargo::crate_root()?; + let workspace_dir = crate::cargo::workspace_root()?; + let target_dir = workspace_dir.join("target"); + let out_dir = crate_dir.join("public"); + let cargo_def = &crate_dir.join("Cargo.toml"); + let static_dir = crate_dir.join("static"); + + let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap(); + + // We just assume they're using a 'main.rs' + // Anyway, we've already parsed the manifest, so it should be easy to change the type + let output_filename = (&manifest) + .lib + .as_ref() + .and_then(|lib| lib.name.clone()) + .or_else(|| { + (&manifest) + .package + .as_ref() + .and_then(|pkg| Some(pkg.name.replace("-", "_"))) + .clone() + }) + .expect("No lib found from cargo metadata"); + let executable = ExecutableType::Binary(output_filename); + + let release = false; + + Ok(Self { + out_dir, + crate_dir, + workspace_dir, + target_dir, + static_dir, + manifest, + executable, + release, + }) + } + + pub fn as_example(&mut self, example_name: String) -> &mut Self { + self.executable = ExecutableType::Example(example_name); + self + } + + pub fn with_release(&mut self, release: bool) -> &mut Self { + self.release = release; + self + } + + pub fn with_build_options(&mut self, options: &BuildOptions) { + if let Some(name) = &options.example { + self.as_example(name.clone()); + } + self.release = options.release; + self.out_dir = options.outdir.clone().into(); + } + + pub fn with_develop_options(&mut self, options: &DevelopOptions) { + if let Some(name) = &options.example { + self.as_example(name.clone()); + } + self.release = options.release; + self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path(); + } +} diff --git a/src/develop.rs b/src/develop.rs new file mode 100644 index 000000000..1ae016b0d --- /dev/null +++ b/src/develop.rs @@ -0,0 +1,111 @@ +use crate::{builder::BuildConfig, cli::DevelopOptions, config::Config, error::Result}; +use async_std::prelude::FutureExt; + +use async_std::future; +use async_std::prelude::*; + +use log::info; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +use std::path::PathBuf; +use std::time::Duration; + +pub struct DevelopConfig {} +impl Into for DevelopOptions { + fn into(self) -> DevelopConfig { + DevelopConfig {} + } +} + +pub async fn start(config: &Config, _options: &DevelopConfig) -> Result<()> { + log::info!("Starting development server 🚀"); + + let Config { out_dir, .. } = config; + + // Spawn the server onto a seperate task + // This lets the task progress while we handle file updates + let server = async_std::task::spawn(launch_server(out_dir.clone())); + let watcher = async_std::task::spawn(watch_directory(config.clone())); + + match server.race(watcher).await { + Err(e) => log::warn!("Error running development server, {:?}", e), + _ => {} + } + + Ok(()) +} + +async fn watch_directory(config: Config) -> Result<()> { + // Create a channel to receive the events. + let (watcher_tx, watcher_rx) = async_std::channel::bounded(100); + + // Automatically select the best implementation for your platform. + // You can also access each implementation directly e.g. INotifyWatcher. + let mut watcher: RecommendedWatcher = Watcher::new_immediate(move |res| { + async_std::task::block_on(watcher_tx.send(res)); + }) + .expect("failed to make watcher"); + + let src_dir = crate::cargo::crate_root()?; + + // Add a path to be watched. All files and directories at that path and + // below will be monitored for changes. + watcher + .watch(src_dir.join("src"), RecursiveMode::Recursive) + .expect("Failed to watch dir"); + + watcher + .watch(src_dir.join("examples"), RecursiveMode::Recursive) + .expect("Failed to watch dir"); + + let build_config = BuildConfig::default(); + + 'run: loop { + crate::builder::build(&config, &build_config)?; + + // Wait for the message with a debounce + let _msg = watcher_rx + .recv() + .join(future::ready(1_usize).delay(Duration::from_millis(2000))) + .await; + + info!("File updated, rebuilding app"); + } + Ok(()) +} + +async fn launch_server(outdir: PathBuf) -> Result<()> { + let _crate_dir = crate::cargo::crate_root()?; + let _workspace_dir = crate::cargo::workspace_root()?; + + let mut app = tide::with_state(ServerState::new(outdir.to_owned())); + let p = outdir.display().to_string(); + + app.at("/") + .get(|req: tide::Request| async move { + log::info!("Connected to development server"); + let state = req.state(); + Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?) + }) + .serve_dir(p)?; + + let port = "8080"; + let serve_addr = format!("0.0.0.0:{}", port); + // let serve_addr = format!("127.0.0.1:{}", port); + + info!("App available at http://{}", serve_addr); + app.listen(serve_addr).await?; + Ok(()) +} + +/// https://github.com/http-rs/tide/blob/main/examples/state.rs +/// Tide seems to prefer using state instead of injecting into the app closure +/// The app closure needs to be static and +#[derive(Clone)] +struct ServerState { + serv_path: PathBuf, +} +impl ServerState { + fn new(serv_path: PathBuf) -> Self { + Self { serv_path } + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 000000000..80a884956 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,34 @@ +use thiserror::Error as ThisError; + +pub type Result = std::result::Result; + +#[derive(ThisError, Debug)] +pub enum Error { + /// Used when errors need to propogate but are too unique to be typed + #[error("{0}")] + Unique(String), + + #[error("I/O Error: {0}")] + IO(#[from] std::io::Error), + + #[error("Failed to write error")] + FailedToWrite, + + #[error("Failed to write error")] + CargoError(String), + + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +impl From<&str> for Error { + fn from(s: &str) -> Self { + Error::Unique(s.to_string()) + } +} + +impl From for Error { + fn from(s: String) -> Self { + Error::Unique(s) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..d6e7c838d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,8 @@ +pub mod builder; +pub mod cargo; +pub mod cli; +pub mod config; +pub mod develop; +pub mod error; +pub mod logging; +pub mod watch; diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 000000000..94a9ce85b --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,49 @@ +use fern::colors::{Color, ColoredLevelConfig}; +use log::debug; + +pub fn set_up_logging() { + // configure colors for the whole line + let colors_line = ColoredLevelConfig::new() + .error(Color::Red) + .warn(Color::Yellow) + // we actually don't need to specify the color for debug and info, they are white by default + .info(Color::White) + .debug(Color::White) + // depending on the terminals color scheme, this is the same as the background color + .trace(Color::BrightBlack); + + // configure colors for the name of the level. + // since almost all of them are the same as the color for the whole line, we + // just clone `colors_line` and overwrite our changes + let colors_level = colors_line.clone().info(Color::Green); + // here we set up our fern Dispatch + fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "{color_line}[{level}{color_line}] {message}\x1B[0m", + color_line = format_args!( + "\x1B[{}m", + colors_line.get_color(&record.level()).to_fg_str() + ), + level = colors_level.color(record.level()), + message = message, + )); + }) + // set the default log level. to filter out verbose log messages from dependencies, set + // this to Warn and overwrite the log level for your crate. + .level(log::LevelFilter::Info) + // .level(log::LevelFilter::Warn) + // change log levels for individual modules. Note: This looks for the record's target + // field which defaults to the module path but can be overwritten with the `target` + // parameter: + // `info!(target="special_target", "This log message is about special_target");` + // .level_for("dioxus", log::LevelFilter::Debug) + // .level_for("dioxus", log::LevelFilter::Info) + // .level_for("pretty_colored", log::LevelFilter::Trace) + // output to stdout + .chain(std::io::stdout()) + .apply() + .unwrap(); + + debug!("finished setting up logging! yay!"); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 000000000..7a5df372c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,28 @@ +use diopack::cli::{LaunchCommand, LaunchOptions}; +use dioxus_cli as diopack; + +#[async_std::main] +async fn main() -> diopack::error::Result<()> { + diopack::logging::set_up_logging(); + + let opts: LaunchOptions = argh::from_env(); + let mut config = diopack::config::Config::new()?; + + match opts.command { + LaunchCommand::Build(options) => { + config.with_build_options(&options); + diopack::builder::build(&config, &(options.into()))?; + } + + LaunchCommand::Develop(options) => { + config.with_develop_options(&options); + diopack::develop::start(&config, &(options.into())).await?; + } + + _ => { + todo!("Command not currently implemented"); + } + } + + Ok(()) +} diff --git a/src/watch.rs b/src/watch.rs new file mode 100644 index 000000000..ae39bc670 --- /dev/null +++ b/src/watch.rs @@ -0,0 +1,11 @@ +pub struct Watcher {} + +impl Watcher { + // Spawns a new notify instance that alerts us of changes + pub fn new() -> Self { + Self {} + } + + /// Subsribe to the watcher + pub fn subscribe() {} +} From 7a67964a2fdd81563633635d62f8e3d2e60e0c95 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 7 Jul 2021 16:54:40 -0400 Subject: [PATCH 002/895] wip: rename docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf2e3310a..fc1e5796b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-

📦✨ dioxus-cli

+

📦✨ dioxus-Studio

Tooling to supercharge dioxus projects

From e2a4efeb9ee9ee9d50238514ef7f98eca90a07d4 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 23 Sep 2021 13:33:22 -0400 Subject: [PATCH 003/895] wip: bump versions --- Cargo.toml | 6 +++--- src/develop.rs | 6 +++--- src/main.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 299a26ae6..b57f28140 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,13 @@ description = "CLI tool for developing, testing, and publishing Dioxus apps" [dependencies] thiserror = "1.0.23" log = "0.4.13" -fern = { version="0.6.0", features=["colored"] } -wasm-bindgen-cli-support = "0.2.73" +fern = { version = "0.6.0", features = ["colored"] } +wasm-bindgen-cli-support = "0.2.78" anyhow = "1.0.38" argh = "0.1.4" serde = "1.0.120" serde_json = "1.0.61" -async-std = { version="1.9.0", features=["attributes"] } +async-std = { version = "1.9.0", features = ["attributes"] } tide = "0.15.0" fs_extra = "1.2.0" diff --git a/src/develop.rs b/src/develop.rs index 1ae016b0d..48565e311 100644 --- a/src/develop.rs +++ b/src/develop.rs @@ -40,7 +40,7 @@ async fn watch_directory(config: Config) -> Result<()> { // Automatically select the best implementation for your platform. // You can also access each implementation directly e.g. INotifyWatcher. - let mut watcher: RecommendedWatcher = Watcher::new_immediate(move |res| { + let mut watcher: RecommendedWatcher = Watcher::new(move |res| { async_std::task::block_on(watcher_tx.send(res)); }) .expect("failed to make watcher"); @@ -50,11 +50,11 @@ async fn watch_directory(config: Config) -> Result<()> { // Add a path to be watched. All files and directories at that path and // below will be monitored for changes. watcher - .watch(src_dir.join("src"), RecursiveMode::Recursive) + .watch(&src_dir.join("src"), RecursiveMode::Recursive) .expect("Failed to watch dir"); watcher - .watch(src_dir.join("examples"), RecursiveMode::Recursive) + .watch(&src_dir.join("examples"), RecursiveMode::Recursive) .expect("Failed to watch dir"); let build_config = BuildConfig::default(); diff --git a/src/main.rs b/src/main.rs index 7a5df372c..8b7ce240d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use diopack::cli::{LaunchCommand, LaunchOptions}; -use dioxus_cli as diopack; +use dioxus_studio as diopack; +use dioxus_studio::cli::{LaunchCommand, LaunchOptions}; #[async_std::main] async fn main() -> diopack::error::Result<()> { From f81183e2a6bd12224afa840a233b3fbbeb38c164 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 10 Oct 2021 15:42:16 -0400 Subject: [PATCH 004/895] feat: remove tailwind from tempalte --- src/builder.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 1d06b3ae8..6b61c8665 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -127,10 +127,6 @@ fn gen_page(module: &str) -> String { - @@ -138,6 +134,7 @@ fn gen_page(module: &str) -> String { import init from "{}"; init("./wasm/module_bg.wasm"); +
"#, From 0966653630a5b2ee06fd4a66f98e3c5b4196aa25 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 29 Dec 2021 11:57:30 -0500 Subject: [PATCH 005/895] docs: fix readme --- README.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fc1e5796b..9f436199c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ # About --- -dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development just a simple two commands: `cargo init` and `dioxus-cli publish`. +dioxus-studio (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development just a simple two commands: `cargo init` and `dioxus-cli publish`. Best thing: - No NPM. @@ -18,6 +18,17 @@ Best thing: - No rollup - No ESLint + +## Visual Studio +Dioxus Studio features a command-line driven visual interface to manage your project. It's a great way to get started with dioxus projects. + +To start the visual environment, simply type `dioxus studio` in your terminal. + +From there, you can explore all the options to build, bundle, and deploy your app. + + +## Features + Just install Rust, dioxus-cli, and you're good to go. `cargo install --git github.com/jkelleyrtp/dioxus-cli` @@ -33,12 +44,12 @@ Need to benchmark a component? Need to test your code? `dioxus test` +Need to convert some html into rsx? +`dioxus convert file.html >> file.rs` + Need to build your code into a bundle? `dioxus build --outdir public` -Need to publish your code to GitHub pages, Netlify, etc? -`dioxus publish --ghpages myrepo.git` - # Use in your project --- Sometimes you'll want to include static assets without bundling them into your .wasm content. dioxus-cli provides a few ways of doing this: From 5fdb14446bb88cddd89179e909081d757204c924 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 29 Dec 2021 12:03:18 -0500 Subject: [PATCH 006/895] wip: studio upgrades --- .vscode/settings.json | 4 +- Cargo.toml | 9 +- src/builder.rs | 26 ++++-- src/cli.rs | 45 ++++++++-- src/config.rs | 5 +- src/develop.rs | 76 ++++++++++++----- src/err.html | 19 +++++ src/error.rs | 3 + src/lib.rs | 29 +++++-- src/logging.rs | 2 - src/main.rs | 24 +----- src/studio.rs | 194 ++++++++++++++++++++++++++++++++++++++++++ src/translate.rs | 101 ++++++++++++++++++++++ tests/test.html | 32 +++++++ 14 files changed, 499 insertions(+), 70 deletions(-) create mode 100644 src/err.html create mode 100644 src/studio.rs create mode 100644 src/translate.rs create mode 100644 tests/test.html diff --git a/.vscode/settings.json b/.vscode/settings.json index 80f51cff8..1c68f97cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.inlayHints.enable": false -} \ No newline at end of file + "rust-analyzer.inlayHints.enable": true +} diff --git a/Cargo.toml b/Cargo.toml index b57f28140..99d6ff539 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,14 +18,19 @@ argh = "0.1.4" serde = "1.0.120" serde_json = "1.0.61" async-std = { version = "1.9.0", features = ["attributes"] } -tide = "0.15.0" +tide = "0.16.0" fs_extra = "1.2.0" -cargo_toml = "0.8.1" +cargo_toml = "0.10.0" futures = "0.3.12" notify = "5.0.0-pre.4" rjdebounce = "0.2.1" tempfile = "3.2.0" +html_parser = "0.6.2" + +tui = { version = "0.15.0", features = ["crossterm"] } +crossterm = "0.19.0" +tui-template = { git = "https://github.com/jkelleyrtp/tui-builder.git" } [[bin]] diff --git a/src/builder.rs b/src/builder.rs index 6b61c8665..83a6d1de5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,10 +1,13 @@ use crate::{ cli::BuildOptions, - config::{Config, ExecutableType}, - error::Result, + config::{CrateConfig, ExecutableType}, + error::{Error, Result}, }; use log::{info, warn}; -use std::{io::Write, process::Command}; +use std::{ + io::{Read, Write}, + process::Command, +}; use wasm_bindgen_cli_support::Bindgen; pub struct BuildConfig {} @@ -19,7 +22,7 @@ impl Default for BuildConfig { } } -pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> { +pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> { /* [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) [2] Generate the appropriate build folders @@ -28,7 +31,7 @@ pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> { [5] Link up the html page to the wasm module */ - let Config { + let CrateConfig { out_dir, crate_dir, target_dir, @@ -60,9 +63,16 @@ pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> { }; let mut child = cmd.spawn()?; - let _err_code = child.wait()?; + let output = child.wait()?; - info!("Build complete!"); + if output.success() { + info!("Build complete!"); + } else { + log::error!("Build failed!"); + let mut reason = String::new(); + child.stderr.unwrap().read_to_string(&mut reason)?; + return Err(Error::BuildFailed(reason)); + } // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("wasm"); @@ -129,6 +139,8 @@ fn gen_page(module: &str) -> String { +
+
diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index f4b69d5d7..58d797485 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -13,8 +13,7 @@ pub struct Build { impl Build { pub fn build(self) -> anyhow::Result<()> { - - let mut crate_config = crate::CrateConfig::new()?; + let mut crate_config = crate::CrateConfig::new()?; // change the relase state. crate_config.with_release(self.build.release); @@ -23,4 +22,4 @@ impl Build { Ok(()) } -} \ No newline at end of file +} diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index feab0e61f..5736ebc19 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -67,6 +67,26 @@ pub struct ConfigOptsBuild { pub pattern_params: Option>, } +#[derive(Clone, Debug, Default, Deserialize, StructOpt)] +pub struct ConfigOptsServe { + /// The index HTML file to drive the bundling process [default: index.html] + #[structopt(parse(from_os_str))] + pub target: Option, + + /// Build in release mode [default: false] + #[structopt(long)] + #[serde(default)] + pub release: bool, + + /// The output dir for all final assets [default: dist] + #[structopt(short, long, parse(from_os_str))] + pub dist: Option, + + /// The public URL from which assets are to be served [default: /] + #[structopt(long, parse(from_str=parse_public_url))] + pub public_url: Option, +} + /// Ensure the given value for `--public-url` is formatted correctly. pub fn parse_public_url(val: &str) -> String { let prefix = if !val.starts_with('/') { "/" } else { "" }; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index fa3bd2c77..32492459a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -35,7 +35,6 @@ pub enum Commands { Translate(translate::Translate), // /// Build, watch & serve the Rust WASM app and all of its assets. Serve(serve::Serve), - // /// Clean output artifacts. // Clean(clean::Clean), diff --git a/src/cli/serve/develop.rs b/src/cli/serve/develop.rs index dd386b14e..27aba99ee 100644 --- a/src/cli/serve/develop.rs +++ b/src/cli/serve/develop.rs @@ -1,145 +1,145 @@ -use crate::{cli::DevelopOptions, config::CrateConfig, error::Result}; -use async_std::prelude::FutureExt; +// use crate::{cli::DevelopOptions, config::CrateConfig, error::Result}; +// use async_std::prelude::FutureExt; -use log::info; -use notify::{RecommendedWatcher, RecursiveMode, Watcher}; -use std::path::PathBuf; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; -use tide::http::mime::HTML; -use tide::http::Mime; +// use log::info; +// use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +// use std::path::PathBuf; +// use std::sync::atomic::AtomicBool; +// use std::sync::Arc; +// use tide::http::mime::HTML; +// use tide::http::Mime; -pub struct DevelopState { - // - reload_on_change: bool, -} +// pub struct DevelopState { +// // +// reload_on_change: bool, +// } -pub async fn develop(options: DevelopOptions) -> Result<()> { - // - log::info!("Starting development server 🚀"); - let mut cfg = CrateConfig::new()?; - cfg.with_develop_options(&options); +// pub async fn develop(options: DevelopOptions) -> Result<()> { +// // +// log::info!("Starting development server 🚀"); +// let mut cfg = CrateConfig::new()?; +// cfg.with_develop_options(&options); - let out_dir = cfg.out_dir.clone(); +// let out_dir = cfg.out_dir.clone(); - let is_err = Arc::new(AtomicBool::new(false)); +// let is_err = Arc::new(AtomicBool::new(false)); - // Spawn the server onto a seperate task - // This lets the task progress while we handle file updates - let server = async_std::task::spawn(launch_server(out_dir, is_err.clone())); - let watcher = async_std::task::spawn(watch_directory(cfg.clone(), is_err.clone())); +// // Spawn the server onto a seperate task +// // This lets the task progress while we handle file updates +// let server = async_std::task::spawn(launch_server(out_dir, is_err.clone())); +// let watcher = async_std::task::spawn(watch_directory(cfg.clone(), is_err.clone())); - match server.race(watcher).await { - Err(e) => log::warn!("Error running development server, {:?}", e), - _ => {} - } +// match server.race(watcher).await { +// Err(e) => log::warn!("Error running development server, {:?}", e), +// _ => {} +// } - Ok(()) -} +// Ok(()) +// } -async fn watch_directory(config: CrateConfig, is_err: ErrStatus) -> Result<()> { - // Create a channel to receive the events. - let (watcher_tx, watcher_rx) = async_std::channel::bounded(100); +// async fn watch_directory(config: CrateConfig, is_err: ErrStatus) -> Result<()> { +// // Create a channel to receive the events. +// let (watcher_tx, watcher_rx) = async_std::channel::bounded(100); - // Automatically select the best implementation for your platform. - // You can also access each implementation directly e.g. INotifyWatcher. - let mut watcher: RecommendedWatcher = Watcher::new(move |res| { - async_std::task::block_on(watcher_tx.send(res)); - // send an event - let _ = async_std::task::block_on(watcher_tx.send(res)); - }) - .expect("failed to make watcher"); +// // Automatically select the best implementation for your platform. +// // You can also access each implementation directly e.g. INotifyWatcher. +// let mut watcher: RecommendedWatcher = Watcher::new(move |res| { +// async_std::task::block_on(watcher_tx.send(res)); +// // send an event +// let _ = async_std::task::block_on(watcher_tx.send(res)); +// }) +// .expect("failed to make watcher"); - let src_dir = crate::cargo::crate_root()?; +// let src_dir = crate::cargo::crate_root()?; - // Add a path to be watched. All files and directories at that path and - // below will be monitored for changes. - watcher - .watch(&src_dir.join("src"), RecursiveMode::Recursive) - .expect("Failed to watch dir"); +// // Add a path to be watched. All files and directories at that path and +// // below will be monitored for changes. +// watcher +// .watch(&src_dir.join("src"), RecursiveMode::Recursive) +// .expect("Failed to watch dir"); - match watcher.watch(&src_dir.join("examples"), RecursiveMode::Recursive) { - Ok(_) => {} - Err(e) => log::warn!("Failed to watch examples dir, {:?}", e), - } +// match watcher.watch(&src_dir.join("examples"), RecursiveMode::Recursive) { +// Ok(_) => {} +// Err(e) => log::warn!("Failed to watch examples dir, {:?}", e), +// } - 'run: loop { - match crate::builder::build(&config) { - Ok(_) => { - is_err.store(false, std::sync::atomic::Ordering::Relaxed); - async_std::task::sleep(std::time::Duration::from_millis(500)).await; - } - Err(err) => is_err.store(true, std::sync::atomic::Ordering::Relaxed), - }; +// 'run: loop { +// match crate::builder::build(&config) { +// Ok(_) => { +// is_err.store(false, std::sync::atomic::Ordering::Relaxed); +// async_std::task::sleep(std::time::Duration::from_millis(500)).await; +// } +// Err(err) => is_err.store(true, std::sync::atomic::Ordering::Relaxed), +// }; - let mut msg = None; - loop { - let new_msg = watcher_rx.recv().await.unwrap().unwrap(); - if !watcher_rx.is_empty() { - msg = Some(new_msg); - break; - } - } +// let mut msg = None; +// loop { +// let new_msg = watcher_rx.recv().await.unwrap().unwrap(); +// if !watcher_rx.is_empty() { +// msg = Some(new_msg); +// break; +// } +// } - info!("File updated, rebuilding app"); - } - Ok(()) -} +// info!("File updated, rebuilding app"); +// } +// Ok(()) +// } -async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> { - let _crate_dir = crate::cargo::crate_root()?; - let _workspace_dir = crate::cargo::workspace_root()?; +// async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> { +// let _crate_dir = crate::cargo::crate_root()?; +// let _workspace_dir = crate::cargo::workspace_root()?; - let mut app = tide::with_state(ServerState::new(outdir.to_owned(), is_err)); +// let mut app = tide::with_state(ServerState::new(outdir.to_owned(), is_err)); - let file_path = format!("{}/index.html", outdir.display()); - log::info!("Serving {}", file_path); - let p = outdir.display().to_string(); +// let file_path = format!("{}/index.html", outdir.display()); +// log::info!("Serving {}", file_path); +// let p = outdir.display().to_string(); - app.at("/") - .get(|req: tide::Request| async move { - log::info!("Connected to development server"); - let state = req.state(); +// app.at("/") +// .get(|req: tide::Request| async move { +// log::info!("Connected to development server"); +// let state = req.state(); - match state.is_err.load(std::sync::atomic::Ordering::Relaxed) { - true => { - // - let mut resp = - tide::Body::from_string(format!(include_str!("../err.html"), err = "_")); - resp.set_mime(HTML); +// match state.is_err.load(std::sync::atomic::Ordering::Relaxed) { +// true => { +// // +// let mut resp = +// tide::Body::from_string(format!(include_str!("../err.html"), err = "_")); +// resp.set_mime(HTML); - Ok(resp) - } - false => { - Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?) - } - } - }) - .serve_dir(p)?; - // .serve_file(file_path) - // .unwrap(); +// Ok(resp) +// } +// false => { +// Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?) +// } +// } +// }) +// .serve_dir(p)?; +// // .serve_file(file_path) +// // .unwrap(); - let port = "8080"; - let serve_addr = format!("127.0.0.1:{}", port); +// let port = "8080"; +// let serve_addr = format!("127.0.0.1:{}", port); - info!("App available at http://{}/", serve_addr); - app.listen(serve_addr).await?; - Ok(()) -} +// info!("App available at http://{}/", serve_addr); +// app.listen(serve_addr).await?; +// Ok(()) +// } -/// https://github.com/http-rs/tide/blob/main/examples/state.rs -/// Tide seems to prefer using state instead of injecting into the app closure -/// The app closure needs to be static and -#[derive(Clone)] -struct ServerState { - serv_path: PathBuf, - is_err: ErrStatus, -} +// /// https://github.com/http-rs/tide/blob/main/examples/state.rs +// /// Tide seems to prefer using state instead of injecting into the app closure +// /// The app closure needs to be static and +// #[derive(Clone)] +// struct ServerState { +// serv_path: PathBuf, +// is_err: ErrStatus, +// } -type ErrStatus = Arc; +// type ErrStatus = Arc; -impl ServerState { - fn new(serv_path: PathBuf, is_err: ErrStatus) -> Self { - Self { serv_path, is_err } - } -} +// impl ServerState { +// fn new(serv_path: PathBuf, is_err: ErrStatus) -> Self { +// Self { serv_path, is_err } +// } +// } diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 9695870c0..36c050bd3 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,9 +1,36 @@ -use crate::cfg::ConfigOptsBuild; +use crate::{cfg::ConfigOptsServe, server}; use anyhow::Result; use std::path::PathBuf; +use std::io::Write; use structopt::StructOpt; -/// Build the Rust WASM app and all of its assets. +mod develop; + +/// Run the WASM project on dev-server #[derive(Clone, Debug, StructOpt)] #[structopt(name = "serve")] -pub struct Serve {} +pub struct Serve { + #[structopt(flatten)] + pub serve: ConfigOptsServe, +} + +impl Serve { + pub async fn serve(self) -> anyhow::Result<()> { + + let mut crate_config = crate::CrateConfig::new()?; + // change the relase state. + crate_config.with_release(self.serve.release); + + crate::builder::build(&crate_config).expect("build failed"); + + let serve_html = String::from(include_str!("../../server/serve.html")); + + let mut file = std::fs::File::create(crate_config.out_dir.join("index.html"))?; + file.write_all(serve_html.as_bytes())?; + + // start the develop server + server::startup(crate_config.clone()).await?; + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index ea8393484..d4d3d7953 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod builder; +pub mod server; pub use builder::*; pub mod cargo; @@ -16,4 +17,4 @@ pub use error::*; pub mod logging; pub use logging::*; -pub mod watch; \ No newline at end of file +pub mod watch; diff --git a/src/main.rs b/src/main.rs index 2ec44eb97..a58794783 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,30 +3,28 @@ use structopt::StructOpt; #[tokio::main] async fn main() -> Result<()> { - let args = Cli::from_args(); set_up_logging(); match args.action { Commands::Translate(opts) => { opts.translate(); - } - + } + Commands::Build(opts) => { opts.build(); } - // Commands::Clean(_) => { - // // - // } + // Commands::Clean(_) => { + // // + // } - // Commands::Config(_) => { - // // - // } - - Commands::Serve(_) => { - // - } + // Commands::Config(_) => { + // // + // } + Commands::Serve(opts) => { + opts.serve().await; + } } Ok(()) diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 000000000..2e937dbb8 --- /dev/null +++ b/src/server/mod.rs @@ -0,0 +1,87 @@ +use axum::{ + extract::{ + ws::{Message, WebSocket}, + Extension, TypedHeader, WebSocketUpgrade, + }, + http::StatusCode, + response::IntoResponse, + routing::{get, get_service}, + AddExtensionLayer, Router, +}; +use notify::{watcher, Watcher, DebouncedEvent}; +use std::sync::{mpsc::channel, Arc, Mutex}; +use std::time::Duration; +use tower_http::services::ServeDir; + +use crate::{CrateConfig, builder}; + +struct WsRelodState { + update: bool, +} + +impl WsRelodState { fn change(&mut self) { self.update = !self.update } } + +pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { + + log::info!("Starting development server 🚀"); + + let (tx, rx) = channel(); + + let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); + watcher.watch(config.crate_dir.join("src").clone(), notify::RecursiveMode::Recursive).unwrap(); + + let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false })); + + let watcher_conf = config.clone(); + let watcher_ws_state = ws_reload_state.clone(); + tokio::spawn(async move { + loop { + if let Ok(v) = rx.recv() { + match v { + DebouncedEvent::Create(_) | DebouncedEvent::Write(_) | + DebouncedEvent::Remove(_) | DebouncedEvent::Rename(_, _) => { + builder::build(&watcher_conf).unwrap(); + watcher_ws_state.lock().unwrap().change(); + }, + _ => {} + } + } + } + }); + + let app = Router::new() + .route("/ws", get(ws_handler)) + .fallback( + get_service(ServeDir::new(config.out_dir)).handle_error( + |error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }, + ), + ) + .layer(AddExtensionLayer::new(ws_reload_state.clone())); + + let port = "8080"; + axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) + .serve(app.into_make_service()) + .await?; + + Ok(()) +} + +async fn ws_handler( + ws: WebSocketUpgrade, + _: Option>, + Extension(state): Extension>>, +) -> impl IntoResponse { + ws.on_upgrade(|mut socket| async move { + loop { + if state.lock().unwrap().update { + socket.send(Message::Text(String::from("reload"))).await.unwrap(); + state.lock().unwrap().change(); + } + } + }) +} diff --git a/src/server/serve.html b/src/server/serve.html new file mode 100644 index 000000000..98997403b --- /dev/null +++ b/src/server/serve.html @@ -0,0 +1,28 @@ + + + + + Dioxus-CLI Dev Server + + +
+ + + + + + + From d18a93f129132bd1ea59344fe757389eae603edc Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sat, 22 Jan 2022 22:19:59 +0800 Subject: [PATCH 022/895] fix: fixed warn info --- src/builder.rs | 24 +++++++++++------------- src/cli/build/mod.rs | 4 +--- src/cli/cfg.rs | 5 +---- src/cli/clean/mod.rs | 3 --- src/cli/mod.rs | 2 -- src/cli/serve/mod.rs | 2 -- src/cli/translate/to_component.rs | 1 + src/config.rs | 2 +- src/main.rs | 6 +++--- src/server/mod.rs | 11 ++++++----- src/server/serve.html | 27 +++++++++++++++++++-------- 11 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 89451e163..101d31ee5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -3,7 +3,7 @@ use crate::{ error::{Error, Result}, }; use std::{ - io::{Read, Write}, + io::Write, process::Command, }; use wasm_bindgen_cli_support::Bindgen; @@ -29,14 +29,15 @@ pub fn build(config: &CrateConfig) -> Result<()> { let t_start = std::time::Instant::now(); // [1] Build the .wasm module - log::info!("Running build commands..."); + log::info!("🚅 Running build commands..."); let mut cmd = Command::new("cargo"); cmd.current_dir(&crate_dir) .arg("build") .arg("--target") .arg("wasm32-unknown-unknown") - .stdout(std::process::Stdio::piped()) - .stderr(std::process::Stdio::piped()); + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()) + ; if config.release { cmd.arg("--release"); @@ -48,16 +49,13 @@ pub fn build(config: &CrateConfig) -> Result<()> { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; - let mut child = cmd.spawn()?; + let output = cmd.output()?; - let output = child.wait()?; - - if output.success() { - log::info!("Build complete!"); + if output.status.success() { + std::io::stdout().write_all(&output.stdout).unwrap(); } else { log::error!("Build failed!"); - let mut reason = String::new(); - child.stderr.unwrap().read_to_string(&mut reason)?; + let reason = String::from_utf8_lossy(&output.stderr).to_string(); return Err(Error::BuildFailed(reason)); } @@ -98,8 +96,8 @@ pub fn build(config: &CrateConfig) -> Result<()> { // [5] Generate the html file with the module name // TODO: support names via options - log::info!("Writing to '{:#?}' directory...", out_dir); + // log::info!("Writing to '{:#?}' directory...", out_dir); let copy_options = fs_extra::dir::CopyOptions::new(); if static_dir.is_dir() { match fs_extra::dir::copy(static_dir, out_dir, ©_options) { @@ -111,7 +109,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { } let t_end = std::time::Instant::now(); - log::info!("Done in {}ms! 🎉", (t_end - t_start).as_millis()); + log::info!("🏁 Done in {}ms!", (t_end - t_start).as_millis()); Ok(()) } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 58d797485..fc329a305 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,6 +1,4 @@ use crate::cfg::ConfigOptsBuild; -use anyhow::Result; -use std::path::PathBuf; use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. @@ -18,7 +16,7 @@ impl Build { // change the relase state. crate_config.with_release(self.build.release); - crate::builder::build(&crate_config); + crate::builder::build(&crate_config)?; Ok(()) } diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 5736ebc19..2c5f42a26 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -1,11 +1,8 @@ -use anyhow::Result; use std::path::PathBuf; use structopt::StructOpt; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::collections::HashMap; -use std::str::FromStr; -use std::sync::Arc; /// Config options for the build system. #[derive(Clone, Debug, Default, Deserialize, StructOpt)] diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index aeeedf523..1edcd053a 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -1,6 +1,3 @@ -use crate::cfg::ConfigOptsBuild; -use anyhow::Result; -use std::path::PathBuf; use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 32492459a..a739f9a01 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,5 +1,3 @@ -use anyhow::{Context, Result}; -use std::path::PathBuf; use structopt::StructOpt; pub mod build; diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 36c050bd3..f2ac2b69f 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,6 +1,4 @@ use crate::{cfg::ConfigOptsServe, server}; -use anyhow::Result; -use std::path::PathBuf; use std::io::Write; use structopt::StructOpt; diff --git a/src/cli/translate/to_component.rs b/src/cli/translate/to_component.rs index b08161e9c..d64854d37 100644 --- a/src/cli/translate/to_component.rs +++ b/src/cli/translate/to_component.rs @@ -20,6 +20,7 @@ pub fn convert_html_to_component(html: &str) -> Result { }) } +#[allow(dead_code)] pub struct ComponentRenderer { dom: Dom, icon_index: usize, diff --git a/src/config.rs b/src/config.rs index 47920c583..d17294b18 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,5 @@ use crate::error::Result; -use std::{io::Write, path::PathBuf, process::Command}; +use std::path::PathBuf; #[derive(Debug, Clone)] pub struct CrateConfig { diff --git a/src/main.rs b/src/main.rs index a58794783..41fa5835b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,11 @@ async fn main() -> Result<()> { match args.action { Commands::Translate(opts) => { - opts.translate(); + opts.translate()?; } Commands::Build(opts) => { - opts.build(); + opts.build()?; } // Commands::Clean(_) => { @@ -23,7 +23,7 @@ async fn main() -> Result<()> { // // // } Commands::Serve(opts) => { - opts.serve().await; + opts.serve().await?; } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 2e937dbb8..6c6c08c1f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,6 +1,6 @@ use axum::{ extract::{ - ws::{Message, WebSocket}, + ws::Message, Extension, TypedHeader, WebSocketUpgrade, }, http::StatusCode, @@ -19,11 +19,11 @@ struct WsRelodState { update: bool, } -impl WsRelodState { fn change(&mut self) { self.update = !self.update } } +impl WsRelodState { fn change(&mut self) { self.update = !self.update; } } pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { - log::info!("Starting development server 🚀"); + log::info!("🚀 Starting development server..."); let (tx, rx) = channel(); @@ -40,8 +40,9 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { match v { DebouncedEvent::Create(_) | DebouncedEvent::Write(_) | DebouncedEvent::Remove(_) | DebouncedEvent::Rename(_, _) => { - builder::build(&watcher_conf).unwrap(); - watcher_ws_state.lock().unwrap().change(); + if let Ok(_) = builder::build(&watcher_conf) { + watcher_ws_state.lock().unwrap().change(); + } }, _ => {} } diff --git a/src/server/serve.html b/src/server/serve.html index 98997403b..b5268bd68 100644 --- a/src/server/serve.html +++ b/src/server/serve.html @@ -14,15 +14,26 @@ From 0e2c05be66fc994ad8ac2e03b34c0e48632c3296 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 23 Jan 2022 01:29:36 +0800 Subject: [PATCH 023/895] feat: add `init` command --- README.md | 5 +- src/builder.rs | 8 +- src/cli/init/mod.rs | 61 +++++++++++++ src/cli/mod.rs | 8 +- src/cli/serve/develop.rs | 145 ------------------------------ src/cli/serve/events.rs | 0 src/cli/serve/mod.rs | 3 - src/cli/translate/to_component.rs | 1 + src/lib.rs | 4 +- src/main.rs | 18 +++- src/{ => server}/err.html | 0 src/server/mod.rs | 64 +++++++------ src/template/config.toml | 9 ++ src/template/default.rs | 16 ++++ src/watch.rs | 1 - 15 files changed, 151 insertions(+), 192 deletions(-) create mode 100644 src/cli/init/mod.rs delete mode 100644 src/cli/serve/develop.rs delete mode 100644 src/cli/serve/events.rs rename src/{ => server}/err.html (100%) create mode 100644 src/template/config.toml create mode 100644 src/template/default.rs delete mode 100644 src/watch.rs diff --git a/README.md b/README.md index 34be58eda..75e05b3cf 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ # About -dioxus-studio (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development simple. +dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development simple. ## Installation @@ -19,5 +19,4 @@ dioxus-studio (inspired by wasm-pack and webpack) is a tool to help get dioxus p $ cargo install dioxus-cli ``` -Now, `dioxus` is in your path. - +Now, `dioxus` is in your path. \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 101d31ee5..24d9c3151 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2,10 +2,7 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, }; -use std::{ - io::Write, - process::Command, -}; +use std::{io::Write, process::Command}; use wasm_bindgen_cli_support::Bindgen; pub fn build(config: &CrateConfig) -> Result<()> { @@ -36,8 +33,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { .arg("--target") .arg("wasm32-unknown-unknown") .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - ; + .stderr(std::process::Stdio::inherit()); if config.release { cmd.arg("--release"); diff --git a/src/cli/init/mod.rs b/src/cli/init/mod.rs new file mode 100644 index 000000000..2325d9c31 --- /dev/null +++ b/src/cli/init/mod.rs @@ -0,0 +1,61 @@ +use std::{process::{Command, Stdio}, fs::File, path::PathBuf, io::Write}; + +use structopt::StructOpt; + +use crate::{error::{Error, Result}, cargo}; + +/// Build the Rust WASM app and all of its assets. +#[derive(Clone, Debug, StructOpt)] +#[structopt(name = "init")] +pub struct Init { + + /// Init project path + #[structopt(default_value = ".")] + path: String, + + /// Template path + #[structopt(default_value = "default", long)] + template: String, + +} + +impl Init { + pub fn init(self) -> Result<()> { + + log::info!("🔧 Start to init a new project '{}'.", self.path); + + let project_path = PathBuf::from(&self.path); + + let output = Command::new("cargo") + .arg("init") + .arg(&self.path) + .arg("--bin") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output()? + ; + + if !output.status.success() { + return Err(Error::CargoError("Cargo init failed".into())); + } + + // get the template code + let template_str = match self.template { + _ => include_str!("../../template/default.rs"), + }; + + let main_rs_file = project_path.join("src").join("main.rs"); + if !main_rs_file.is_file() { + return Err(Error::FailedToWrite); + } + + let mut file = File::create(main_rs_file)?; + file.write_all(&template_str.as_bytes())?; + + // log::info!("🎯 Project initialization completed."); + + + + Ok(()) + } +} \ No newline at end of file diff --git a/src/cli/mod.rs b/src/cli/mod.rs index a739f9a01..ddc55d5c4 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -5,6 +5,7 @@ pub mod cfg; pub mod clean; pub mod serve; pub mod translate; +pub mod init; /// Build, bundle, & ship your Dioxus app. /// @@ -27,12 +28,15 @@ pub struct Cli { #[derive(StructOpt)] pub enum Commands { - // /// Build the Rust WASM app and all of its assets. + /// Build the Rust WASM app and all of its assets. Build(build::Build), /// Translate some source file into Dioxus code. Translate(translate::Translate), - // /// Build, watch & serve the Rust WASM app and all of its assets. + /// Build, watch & serve the Rust WASM app and all of its assets. Serve(serve::Serve), + /// Init a new project for Dioxus. + Init(init::Init), + // /// Clean output artifacts. // Clean(clean::Clean), diff --git a/src/cli/serve/develop.rs b/src/cli/serve/develop.rs deleted file mode 100644 index 27aba99ee..000000000 --- a/src/cli/serve/develop.rs +++ /dev/null @@ -1,145 +0,0 @@ -// use crate::{cli::DevelopOptions, config::CrateConfig, error::Result}; -// use async_std::prelude::FutureExt; - -// use log::info; -// use notify::{RecommendedWatcher, RecursiveMode, Watcher}; -// use std::path::PathBuf; -// use std::sync::atomic::AtomicBool; -// use std::sync::Arc; -// use tide::http::mime::HTML; -// use tide::http::Mime; - -// pub struct DevelopState { -// // -// reload_on_change: bool, -// } - -// pub async fn develop(options: DevelopOptions) -> Result<()> { -// // -// log::info!("Starting development server 🚀"); -// let mut cfg = CrateConfig::new()?; -// cfg.with_develop_options(&options); - -// let out_dir = cfg.out_dir.clone(); - -// let is_err = Arc::new(AtomicBool::new(false)); - -// // Spawn the server onto a seperate task -// // This lets the task progress while we handle file updates -// let server = async_std::task::spawn(launch_server(out_dir, is_err.clone())); -// let watcher = async_std::task::spawn(watch_directory(cfg.clone(), is_err.clone())); - -// match server.race(watcher).await { -// Err(e) => log::warn!("Error running development server, {:?}", e), -// _ => {} -// } - -// Ok(()) -// } - -// async fn watch_directory(config: CrateConfig, is_err: ErrStatus) -> Result<()> { -// // Create a channel to receive the events. -// let (watcher_tx, watcher_rx) = async_std::channel::bounded(100); - -// // Automatically select the best implementation for your platform. -// // You can also access each implementation directly e.g. INotifyWatcher. -// let mut watcher: RecommendedWatcher = Watcher::new(move |res| { -// async_std::task::block_on(watcher_tx.send(res)); -// // send an event -// let _ = async_std::task::block_on(watcher_tx.send(res)); -// }) -// .expect("failed to make watcher"); - -// let src_dir = crate::cargo::crate_root()?; - -// // Add a path to be watched. All files and directories at that path and -// // below will be monitored for changes. -// watcher -// .watch(&src_dir.join("src"), RecursiveMode::Recursive) -// .expect("Failed to watch dir"); - -// match watcher.watch(&src_dir.join("examples"), RecursiveMode::Recursive) { -// Ok(_) => {} -// Err(e) => log::warn!("Failed to watch examples dir, {:?}", e), -// } - -// 'run: loop { -// match crate::builder::build(&config) { -// Ok(_) => { -// is_err.store(false, std::sync::atomic::Ordering::Relaxed); -// async_std::task::sleep(std::time::Duration::from_millis(500)).await; -// } -// Err(err) => is_err.store(true, std::sync::atomic::Ordering::Relaxed), -// }; - -// let mut msg = None; -// loop { -// let new_msg = watcher_rx.recv().await.unwrap().unwrap(); -// if !watcher_rx.is_empty() { -// msg = Some(new_msg); -// break; -// } -// } - -// info!("File updated, rebuilding app"); -// } -// Ok(()) -// } - -// async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> { -// let _crate_dir = crate::cargo::crate_root()?; -// let _workspace_dir = crate::cargo::workspace_root()?; - -// let mut app = tide::with_state(ServerState::new(outdir.to_owned(), is_err)); - -// let file_path = format!("{}/index.html", outdir.display()); -// log::info!("Serving {}", file_path); -// let p = outdir.display().to_string(); - -// app.at("/") -// .get(|req: tide::Request| async move { -// log::info!("Connected to development server"); -// let state = req.state(); - -// match state.is_err.load(std::sync::atomic::Ordering::Relaxed) { -// true => { -// // -// let mut resp = -// tide::Body::from_string(format!(include_str!("../err.html"), err = "_")); -// resp.set_mime(HTML); - -// Ok(resp) -// } -// false => { -// Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?) -// } -// } -// }) -// .serve_dir(p)?; -// // .serve_file(file_path) -// // .unwrap(); - -// let port = "8080"; -// let serve_addr = format!("127.0.0.1:{}", port); - -// info!("App available at http://{}/", serve_addr); -// app.listen(serve_addr).await?; -// Ok(()) -// } - -// /// https://github.com/http-rs/tide/blob/main/examples/state.rs -// /// Tide seems to prefer using state instead of injecting into the app closure -// /// The app closure needs to be static and -// #[derive(Clone)] -// struct ServerState { -// serv_path: PathBuf, -// is_err: ErrStatus, -// } - -// type ErrStatus = Arc; - -// impl ServerState { -// fn new(serv_path: PathBuf, is_err: ErrStatus) -> Self { -// Self { serv_path, is_err } -// } -// } diff --git a/src/cli/serve/events.rs b/src/cli/serve/events.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index f2ac2b69f..d6287f07d 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -2,8 +2,6 @@ use crate::{cfg::ConfigOptsServe, server}; use std::io::Write; use structopt::StructOpt; -mod develop; - /// Run the WASM project on dev-server #[derive(Clone, Debug, StructOpt)] #[structopt(name = "serve")] @@ -14,7 +12,6 @@ pub struct Serve { impl Serve { pub async fn serve(self) -> anyhow::Result<()> { - let mut crate_config = crate::CrateConfig::new()?; // change the relase state. crate_config.with_release(self.serve.release); diff --git a/src/cli/translate/to_component.rs b/src/cli/translate/to_component.rs index d64854d37..972da7a25 100644 --- a/src/cli/translate/to_component.rs +++ b/src/cli/translate/to_component.rs @@ -4,6 +4,7 @@ //! - [ ] Extracts svgs //! - [ ] Attempts to extract lists +#[allow(unused_imports)] use std::{ fmt::{Display, Formatter}, io::Write, diff --git a/src/lib.rs b/src/lib.rs index d4d3d7953..15c10a3b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,4 @@ pub mod error; pub use error::*; pub mod logging; -pub use logging::*; - -pub mod watch; +pub use logging::*; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 41fa5835b..69636c6e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,15 @@ async fn main() -> Result<()> { match args.action { Commands::Translate(opts) => { - opts.translate()?; + if let Err(e) = opts.translate() { + log::error!("translate error: {}", e); + } } Commands::Build(opts) => { - opts.build()?; + if let Err(e) = opts.build() { + log::error!("build error: {}", e); + } } // Commands::Clean(_) => { @@ -23,7 +27,15 @@ async fn main() -> Result<()> { // // // } Commands::Serve(opts) => { - opts.serve().await?; + if let Err(e) = opts.serve().await { + log::error!("serve error: {}", e); + } + } + + Commands::Init(opts) => { + if let Err(e) = opts.init() { + log::error!("init error: {}", e); + } } } diff --git a/src/err.html b/src/server/err.html similarity index 100% rename from src/err.html rename to src/server/err.html diff --git a/src/server/mod.rs b/src/server/mod.rs index 6c6c08c1f..7c0713c8d 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,34 +1,40 @@ use axum::{ - extract::{ - ws::Message, - Extension, TypedHeader, WebSocketUpgrade, - }, + extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, http::StatusCode, response::IntoResponse, routing::{get, get_service}, AddExtensionLayer, Router, }; -use notify::{watcher, Watcher, DebouncedEvent}; +use notify::{watcher, DebouncedEvent, Watcher}; use std::sync::{mpsc::channel, Arc, Mutex}; use std::time::Duration; use tower_http::services::ServeDir; -use crate::{CrateConfig, builder}; +use crate::{builder, CrateConfig}; struct WsRelodState { update: bool, } -impl WsRelodState { fn change(&mut self) { self.update = !self.update; } } +impl WsRelodState { + fn change(&mut self) { + self.update = !self.update; + } +} pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { - log::info!("🚀 Starting development server..."); - + let (tx, rx) = channel(); + // file watcher: check file change let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); - watcher.watch(config.crate_dir.join("src").clone(), notify::RecursiveMode::Recursive).unwrap(); + watcher + .watch( + config.crate_dir.join("src").clone(), + notify::RecursiveMode::Recursive, + ) + .unwrap(); let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false })); @@ -38,37 +44,40 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { loop { if let Ok(v) = rx.recv() { match v { - DebouncedEvent::Create(_) | DebouncedEvent::Write(_) | - DebouncedEvent::Remove(_) | DebouncedEvent::Rename(_, _) => { + DebouncedEvent::Create(_) + | DebouncedEvent::Write(_) + | DebouncedEvent::Remove(_) + | DebouncedEvent::Rename(_, _) => { if let Ok(_) = builder::build(&watcher_conf) { + // change the websocket reload state to true; + // the page will auto-reload. watcher_ws_state.lock().unwrap().change(); } - }, + } _ => {} } } - } + } }); let app = Router::new() .route("/ws", get(ws_handler)) - .fallback( - get_service(ServeDir::new(config.out_dir)).handle_error( - |error: std::io::Error| async move { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Unhandled internal error: {}", error), - ) - }, - ), - ) + .fallback(get_service(ServeDir::new(config.out_dir)).handle_error( + |error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }, + )) .layer(AddExtensionLayer::new(ws_reload_state.clone())); + // start serve dev-server at 0.0.0.0:8080 let port = "8080"; + log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) .serve(app.into_make_service()) .await?; - Ok(()) } @@ -80,7 +89,10 @@ async fn ws_handler( ws.on_upgrade(|mut socket| async move { loop { if state.lock().unwrap().update { - socket.send(Message::Text(String::from("reload"))).await.unwrap(); + socket + .send(Message::Text(String::from("reload"))) + .await + .unwrap(); state.lock().unwrap().change(); } } diff --git a/src/template/config.toml b/src/template/config.toml new file mode 100644 index 000000000..4c6c2be9c --- /dev/null +++ b/src/template/config.toml @@ -0,0 +1,9 @@ +[package] +name = "{project}" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { version = "0.1.7", features = ["web"] } diff --git a/src/template/default.rs b/src/template/default.rs new file mode 100644 index 000000000..c0fa412ea --- /dev/null +++ b/src/template/default.rs @@ -0,0 +1,16 @@ +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + cx.render(rsx! ( + div { + style: "text-align: center;", + h2 { "🌗🚀 Dioxus" } + p { strong { "Frontend that scales." } } + p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." } + } + )) +} diff --git a/src/watch.rs b/src/watch.rs deleted file mode 100644 index 8b1378917..000000000 --- a/src/watch.rs +++ /dev/null @@ -1 +0,0 @@ - From 5395e7693c05caf5446a1cc6671de7e870366569 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 23 Jan 2022 10:54:24 +0800 Subject: [PATCH 024/895] fix: `dist` setting --- src/builder.rs | 9 +++++---- src/cli/build/mod.rs | 7 ++++++- src/cli/init/mod.rs | 38 +++++++++++++++++++++++++++++--------- src/cli/mod.rs | 3 +-- src/cli/serve/mod.rs | 11 +++++++---- src/lib.rs | 2 +- src/server/mod.rs | 13 ++++++++++--- src/template/config.toml | 2 +- src/template/default.rs | 2 +- 9 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 24d9c3151..aad275ff2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2,10 +2,10 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, }; -use std::{io::Write, process::Command}; +use std::{io::Write, path::PathBuf, process::Command}; use wasm_bindgen_cli_support::Bindgen; -pub fn build(config: &CrateConfig) -> Result<()> { +pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { /* [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) [2] Generate the appropriate build folders @@ -15,7 +15,6 @@ pub fn build(config: &CrateConfig) -> Result<()> { */ let CrateConfig { - out_dir, crate_dir, target_dir, static_dir, @@ -23,10 +22,12 @@ pub fn build(config: &CrateConfig) -> Result<()> { .. } = config; + let out_dir = crate_dir.join(dist); + let t_start = std::time::Instant::now(); // [1] Build the .wasm module - log::info!("🚅 Running build commands..."); + log::info!("🚅 Running build command..."); let mut cmd = Command::new("cargo"); cmd.current_dir(&crate_dir) .arg("build") diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index fc329a305..760c2fd8e 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use crate::cfg::ConfigOptsBuild; use structopt::StructOpt; @@ -16,7 +18,10 @@ impl Build { // change the relase state. crate_config.with_release(self.build.release); - crate::builder::build(&crate_config)?; + crate::builder::build( + &crate_config, + self.build.dist.unwrap_or(PathBuf::from("dist")), + )?; Ok(()) } diff --git a/src/cli/init/mod.rs b/src/cli/init/mod.rs index 2325d9c31..dde0ccca3 100644 --- a/src/cli/init/mod.rs +++ b/src/cli/init/mod.rs @@ -1,14 +1,18 @@ -use std::{process::{Command, Stdio}, fs::File, path::PathBuf, io::Write}; +use std::{ + fs::{File, OpenOptions}, + io::Write, + path::PathBuf, + process::{Command, Stdio}, +}; use structopt::StructOpt; -use crate::{error::{Error, Result}, cargo}; +use crate::error::{Error, Result}; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, StructOpt)] #[structopt(name = "init")] pub struct Init { - /// Init project path #[structopt(default_value = ".")] path: String, @@ -16,24 +20,26 @@ pub struct Init { /// Template path #[structopt(default_value = "default", long)] template: String, - } impl Init { pub fn init(self) -> Result<()> { - log::info!("🔧 Start to init a new project '{}'.", self.path); let project_path = PathBuf::from(&self.path); + if project_path.join("Cargo.toml").is_file() { + log::warn!("Path '{}' is initialized.", self.path); + return Ok(()); + } + let output = Command::new("cargo") .arg("init") .arg(&self.path) .arg("--bin") .stdout(Stdio::piped()) .stderr(Stdio::piped()) - .output()? - ; + .output()?; if !output.status.success() { return Err(Error::CargoError("Cargo init failed".into())); @@ -54,8 +60,22 @@ impl Init { // log::info!("🎯 Project initialization completed."); - + if !Command::new("cargo") + .args(["add", "dioxus", "--features web"]) + .output()? + .status + .success() + { + let mut file = OpenOptions::new() + .append(true) + .open(project_path.join("Cargo.toml"))?; + file.write_all("dioxus = { version = \"0.1.7\", features = [\"web\"] }".as_bytes())?; + } + + log::info!("\n💡 Project initialized:"); + log::info!("🎯> cd {}", self.path); + log::info!("🎯> dioxus serve"); Ok(()) } -} \ No newline at end of file +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ddc55d5c4..93cbfef28 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -3,9 +3,9 @@ use structopt::StructOpt; pub mod build; pub mod cfg; pub mod clean; +pub mod init; pub mod serve; pub mod translate; -pub mod init; /// Build, bundle, & ship your Dioxus app. /// @@ -36,7 +36,6 @@ pub enum Commands { Serve(serve::Serve), /// Init a new project for Dioxus. Init(init::Init), - // /// Clean output artifacts. // Clean(clean::Clean), diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index d6287f07d..586d49b7c 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,5 +1,5 @@ use crate::{cfg::ConfigOptsServe, server}; -use std::io::Write; +use std::{io::Write, path::PathBuf}; use structopt::StructOpt; /// Run the WASM project on dev-server @@ -16,15 +16,18 @@ impl Serve { // change the relase state. crate_config.with_release(self.serve.release); - crate::builder::build(&crate_config).expect("build failed"); + let dist_path = self.serve.dist.clone().unwrap_or(PathBuf::from("dist")); + + crate::builder::build(&crate_config, dist_path.clone()).expect("build failed"); let serve_html = String::from(include_str!("../../server/serve.html")); - let mut file = std::fs::File::create(crate_config.out_dir.join("index.html"))?; + let mut file = + std::fs::File::create(crate_config.crate_dir.join(dist_path).join("index.html"))?; file.write_all(serve_html.as_bytes())?; // start the develop server - server::startup(crate_config.clone()).await?; + server::startup(crate_config.clone(), &self.serve).await?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 15c10a3b3..395cbc8dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,4 +15,4 @@ pub mod error; pub use error::*; pub mod logging; -pub use logging::*; \ No newline at end of file +pub use logging::*; diff --git a/src/server/mod.rs b/src/server/mod.rs index 7c0713c8d..4f04d3268 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,8 +6,11 @@ use axum::{ AddExtensionLayer, Router, }; use notify::{watcher, DebouncedEvent, Watcher}; -use std::sync::{mpsc::channel, Arc, Mutex}; use std::time::Duration; +use std::{ + path::PathBuf, + sync::{mpsc::channel, Arc, Mutex}, +}; use tower_http::services::ServeDir; use crate::{builder, CrateConfig}; @@ -22,7 +25,10 @@ impl WsRelodState { } } -pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { +pub async fn startup( + config: CrateConfig, + opts: &crate::cfg::ConfigOptsServe, +) -> anyhow::Result<()> { log::info!("🚀 Starting development server..."); let (tx, rx) = channel(); @@ -40,6 +46,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { let watcher_conf = config.clone(); let watcher_ws_state = ws_reload_state.clone(); + let dist_path = opts.dist.clone().unwrap_or(PathBuf::from("dist")); tokio::spawn(async move { loop { if let Ok(v) = rx.recv() { @@ -48,7 +55,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { | DebouncedEvent::Write(_) | DebouncedEvent::Remove(_) | DebouncedEvent::Rename(_, _) => { - if let Ok(_) = builder::build(&watcher_conf) { + if let Ok(_) = builder::build(&watcher_conf, dist_path.clone()) { // change the websocket reload state to true; // the page will auto-reload. watcher_ws_state.lock().unwrap().change(); diff --git a/src/template/config.toml b/src/template/config.toml index 4c6c2be9c..9644babc1 100644 --- a/src/template/config.toml +++ b/src/template/config.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dioxus = { version = "0.1.7", features = ["web"] } +dioxus = { version = "0.1.7", features = ["web"] } \ No newline at end of file diff --git a/src/template/default.rs b/src/template/default.rs index c0fa412ea..ac1614fc4 100644 --- a/src/template/default.rs +++ b/src/template/default.rs @@ -1,7 +1,7 @@ use dioxus::prelude::*; fn main() { - dioxus::desktop::launch(app); + dioxus::web::launch(app); } fn app(cx: Scope) -> Element { From 70adff7e443500e05ce8ff32a803971c4f816aff Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 23 Jan 2022 12:11:17 +0800 Subject: [PATCH 025/895] feat: add `dioxus.toml` support --- Cargo.toml | 1 + Dioxus.toml | 42 ++++++++++++++++++++++++++++++++++++++++++ src/builder.rs | 13 ++----------- src/config.rs | 40 +++++++++++++++++++++++++++++++++++++++- src/server/mod.rs | 24 ++++++++++++++---------- 5 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 Dioxus.toml diff --git a/Cargo.toml b/Cargo.toml index cd1dec98b..8bb6fd3ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ wasm-bindgen-cli-support = "0.2.79" anyhow = "1.0.38" serde = { version = "1.0.133", features = ["derive"] } serde_json = "1" +toml = "0.5.8" fs_extra = "1.2.0" cargo_toml = "0.10.0" futures = "0.3.12" diff --git a/Dioxus.toml b/Dioxus.toml new file mode 100644 index 000000000..abd2d1ee4 --- /dev/null +++ b/Dioxus.toml @@ -0,0 +1,42 @@ +[application] + +# App (Project) Name +name = "dioxus-cli" + +# Dioxus App Support Platform +# desktop, web, mobile, ssr +platforms = ["web"] + +[web.app] + +# Web `build` & `serve` dist path +out_dir = "dist" + +# resource (static) file folder +static_dir = "static" + +[web.watcher] + + +watch_path = ["src"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [ + "./my-style.css" +] + +# Javascript code file +script = [ + "./app.js" +] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [ + "./debug.js" +] \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index aad275ff2..58ee085fc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -48,14 +48,12 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { let output = cmd.output()?; - if output.status.success() { - std::io::stdout().write_all(&output.stdout).unwrap(); - } else { + if !output.status.success() { log::error!("Build failed!"); let reason = String::from_utf8_lossy(&output.stderr).to_string(); return Err(Error::BuildFailed(reason)); } - + // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets"); @@ -88,13 +86,6 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { .out_name("module") .generate(&bindgen_outdir)?; - // [4] - // TODO: wasm-opt - - // [5] Generate the html file with the module name - // TODO: support names via options - - // log::info!("Writing to '{:#?}' directory...", out_dir); let copy_options = fs_extra::dir::CopyOptions::new(); if static_dir.is_dir() { match fs_extra::dir::copy(static_dir, out_dir, ©_options) { diff --git a/src/config.rs b/src/config.rs index d17294b18..9d38160f2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,44 @@ use crate::error::Result; +use serde::{Deserialize, Serialize}; use std::path::PathBuf; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DioxusConfig { + application: ApplicationConfig, + web: WebConfig, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ApplicationConfig { + name: String, + platform: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebConfig { + app: WebAppConfing, + watcher: WebWatcherConfing, + resource: WebResourceConfing, +} + + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebAppConfing { + +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebWatcherConfing { + +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebResourceConfing { + +} + + #[derive(Debug, Clone)] pub struct CrateConfig { pub out_dir: PathBuf, @@ -86,4 +124,4 @@ impl CrateConfig { // self.release = options.release; // self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path(); // } -} +} \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index 4f04d3268..6b91a2e71 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -33,6 +33,8 @@ pub async fn startup( let (tx, rx) = channel(); + let dist_path = opts.dist.clone().unwrap_or(PathBuf::from("dist")); + // file watcher: check file change let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); watcher @@ -46,7 +48,7 @@ pub async fn startup( let watcher_conf = config.clone(); let watcher_ws_state = ws_reload_state.clone(); - let dist_path = opts.dist.clone().unwrap_or(PathBuf::from("dist")); + let watcher_dist_path = dist_path.clone(); tokio::spawn(async move { loop { if let Ok(v) = rx.recv() { @@ -55,7 +57,7 @@ pub async fn startup( | DebouncedEvent::Write(_) | DebouncedEvent::Remove(_) | DebouncedEvent::Rename(_, _) => { - if let Ok(_) = builder::build(&watcher_conf, dist_path.clone()) { + if let Ok(_) = builder::build(&watcher_conf, watcher_dist_path.clone()) { // change the websocket reload state to true; // the page will auto-reload. watcher_ws_state.lock().unwrap().change(); @@ -69,14 +71,16 @@ pub async fn startup( let app = Router::new() .route("/ws", get(ws_handler)) - .fallback(get_service(ServeDir::new(config.out_dir)).handle_error( - |error: std::io::Error| async move { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Unhandled internal error: {}", error), - ) - }, - )) + .fallback( + get_service(ServeDir::new(config.crate_dir.join(&dist_path))).handle_error( + |error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }, + ), + ) .layer(AddExtensionLayer::new(ws_reload_state.clone())); // start serve dev-server at 0.0.0.0:8080 From 9bb10c65a3cbabef127f6af5c0d1eadab1d01531 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 23 Jan 2022 17:35:59 +0800 Subject: [PATCH 026/895] feat: add `Dioxus.toml` --- src/assets/autoreload.js | 25 +++++++++++++ src/assets/index.html | 18 +++++++++ src/builder.rs | 81 ++++++++++++++++++++++++++-------------- src/cli/build/mod.rs | 7 +--- src/cli/cfg.rs | 16 -------- src/cli/init/mod.rs | 27 ++++++++++---- src/cli/serve/mod.rs | 28 ++++++++++---- src/config.rs | 78 ++++++++++++++++++++++++++++++-------- src/server/err.html | 19 ---------- src/server/mod.rs | 54 ++++++++++++++++----------- src/server/serve.html | 39 ------------------- src/template/config.toml | 43 +++++++++++++++++---- src/template/default.rs | 4 +- 13 files changed, 269 insertions(+), 170 deletions(-) create mode 100644 src/assets/autoreload.js create mode 100644 src/assets/index.html delete mode 100644 src/server/err.html delete mode 100644 src/server/serve.html diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js new file mode 100644 index 000000000..ff4444085 --- /dev/null +++ b/src/assets/autoreload.js @@ -0,0 +1,25 @@ +(function () { + var protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + + var url = protocol + "//" + window.location.host + "/_dioxus/ws"; + + var poll_interval = 2000; + + var reload_upon_connect = () => { + window.setTimeout(() => { + var ws = new WebSocket(url); + ws.onopen = () => window.location.reload(); + ws.onclose = reload_upon_connect; + }, poll_interval); + }; + + var ws = new WebSocket(url); + + ws.onmessage = (ev) => { + if (ev.data == "reload") { + window.location.reload(); + } + }; + + ws.onclose = reload_upon_connect; +})(); \ No newline at end of file diff --git a/src/assets/index.html b/src/assets/index.html new file mode 100644 index 000000000..12e1e5678 --- /dev/null +++ b/src/assets/index.html @@ -0,0 +1,18 @@ + + + {app_title} + + + {style_include} + + + +
+ + + {script_include} + + diff --git a/src/builder.rs b/src/builder.rs index 58ee085fc..381ef8b28 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,11 +1,12 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, + DioxusConfig, }; -use std::{io::Write, path::PathBuf, process::Command}; +use std::process::Command; use wasm_bindgen_cli_support::Bindgen; -pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { +pub fn build(config: &CrateConfig) -> Result<()> { /* [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) [2] Generate the appropriate build folders @@ -15,15 +16,15 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { */ let CrateConfig { + out_dir, crate_dir, target_dir, static_dir, executable, + dioxus_config, .. } = config; - let out_dir = crate_dir.join(dist); - let t_start = std::time::Instant::now(); // [1] Build the .wasm module @@ -53,7 +54,7 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { let reason = String::from_utf8_lossy(&output.stderr).to_string(); return Err(Error::BuildFailed(reason)); } - + // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets"); @@ -83,7 +84,7 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { .keep_debug(true) .remove_name_section(false) .remove_producers_section(false) - .out_name("module") + .out_name(&dioxus_config.application.name) .generate(&bindgen_outdir)?; let copy_options = fs_extra::dir::CopyOptions::new(); @@ -101,28 +102,52 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> { Ok(()) } -pub fn gen_page(module: &str) -> String { - format!( - r#" - - - - - - -
-
- - -
- - -"#, - module - ) +pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { + let mut html = String::from(include_str!("./assets/index.html")); + + let resouces = config.web.resource.clone(); + + let mut style_list = resouces.style.unwrap_or(vec![]); + let mut script_list = resouces.script.unwrap_or(vec![]); + + if serve { + let mut dev_style = resouces.dev.style.clone().unwrap_or(vec![]); + let mut dev_script = resouces.dev.script.clone().unwrap_or(vec![]); + style_list.append(&mut dev_style); + script_list.append(&mut dev_script); + } + + let mut style_str = String::new(); + for style in style_list { + style_str.push_str(&format!( + "\n", + &style.to_str().unwrap(), + )) + } + html = html.replace("{style_include}", &style_str); + + let mut script_str = String::new(); + for script in script_list { + script_str.push_str(&format!( + "\n", + &script.to_str().unwrap(), + )) + } + + html = html.replace("{script_include}", &script_str); + + if serve { + html += &format!( + "", + include_str!("./assets/autoreload.js") + ); + } + + html = html.replace("{app_name}", &config.application.name); + + let title = config.web.app.title.clone().unwrap_or("dioxus | ⛺".into()); + + html.replace("{app_title}", &title) } // use binary_install::{Cache, Download}; diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 760c2fd8e..fc329a305 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use crate::cfg::ConfigOptsBuild; use structopt::StructOpt; @@ -18,10 +16,7 @@ impl Build { // change the relase state. crate_config.with_release(self.build.release); - crate::builder::build( - &crate_config, - self.build.dist.unwrap_or(PathBuf::from("dist")), - )?; + crate::builder::build(&crate_config)?; Ok(()) } diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 2c5f42a26..ab68ce4f9 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -16,14 +16,6 @@ pub struct ConfigOptsBuild { #[serde(default)] pub release: bool, - /// The output dir for all final assets [default: dist] - #[structopt(short, long, parse(from_os_str))] - pub dist: Option, - - /// The public URL from which assets are to be served [default: /] - #[structopt(long, parse(from_str=parse_public_url))] - pub public_url: Option, - /// Optional pattern for the app loader script [default: None] /// /// Patterns should include the sequences `{base}`, `{wasm}`, and `{js}` in order to @@ -74,14 +66,6 @@ pub struct ConfigOptsServe { #[structopt(long)] #[serde(default)] pub release: bool, - - /// The output dir for all final assets [default: dist] - #[structopt(short, long, parse(from_os_str))] - pub dist: Option, - - /// The public URL from which assets are to be served [default: /] - #[structopt(long, parse(from_str=parse_public_url))] - pub public_url: Option, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/cli/init/mod.rs b/src/cli/init/mod.rs index dde0ccca3..52dcf4c14 100644 --- a/src/cli/init/mod.rs +++ b/src/cli/init/mod.rs @@ -13,9 +13,9 @@ use crate::error::{Error, Result}; #[derive(Clone, Debug, StructOpt)] #[structopt(name = "init")] pub struct Init { - /// Init project path + /// Init project name #[structopt(default_value = ".")] - path: String, + name: String, /// Template path #[structopt(default_value = "default", long)] @@ -24,18 +24,23 @@ pub struct Init { impl Init { pub fn init(self) -> Result<()> { - log::info!("🔧 Start to init a new project '{}'.", self.path); + if self.name.contains(".") { + log::error!("❗Unsupported project name."); + return Ok(()); + } - let project_path = PathBuf::from(&self.path); + log::info!("🔧 Start to init a new project '{}'.", self.name); + + let project_path = PathBuf::from(&self.name); if project_path.join("Cargo.toml").is_file() { - log::warn!("Path '{}' is initialized.", self.path); + log::warn!("Folder '{}' is initialized.", self.name); return Ok(()); } let output = Command::new("cargo") .arg("init") - .arg(&self.path) + .arg(&format!("./{}", self.name)) .arg("--bin") .stdout(Stdio::piped()) .stderr(Stdio::piped()) @@ -58,6 +63,11 @@ impl Init { let mut file = File::create(main_rs_file)?; file.write_all(&template_str.as_bytes())?; + let mut file = File::create(project_path.join("Dioxus.toml"))?; + let dioxus_conf = String::from(include_str!("../../template/config.toml")) + .replace("{project-name}", &self.name); + file.write_all(dioxus_conf.as_bytes())?; + // log::info!("🎯 Project initialization completed."); if !Command::new("cargo") @@ -72,8 +82,9 @@ impl Init { file.write_all("dioxus = { version = \"0.1.7\", features = [\"web\"] }".as_bytes())?; } - log::info!("\n💡 Project initialized:"); - log::info!("🎯> cd {}", self.path); + println!(""); + log::info!("💡 Project initialized:"); + log::info!("🎯> cd ./{}", self.name); log::info!("🎯> dioxus serve"); Ok(()) diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 586d49b7c..7d580f7fb 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,4 +1,4 @@ -use crate::{cfg::ConfigOptsServe, server}; +use crate::{cfg::ConfigOptsServe, gen_page, server}; use std::{io::Write, path::PathBuf}; use structopt::StructOpt; @@ -16,19 +16,31 @@ impl Serve { // change the relase state. crate_config.with_release(self.serve.release); - let dist_path = self.serve.dist.clone().unwrap_or(PathBuf::from("dist")); + crate::builder::build(&crate_config).expect("build failed"); - crate::builder::build(&crate_config, dist_path.clone()).expect("build failed"); + let serve_html = gen_page(&crate_config.dioxus_config, true); - let serve_html = String::from(include_str!("../../server/serve.html")); - - let mut file = - std::fs::File::create(crate_config.crate_dir.join(dist_path).join("index.html"))?; + let mut file = std::fs::File::create( + crate_config + .crate_dir + .join( + crate_config + .dioxus_config + .web + .app + .out_dir + .clone() + .unwrap_or(PathBuf::from("dist")), + ) + .join("index.html"), + )?; file.write_all(serve_html.as_bytes())?; // start the develop server - server::startup(crate_config.clone(), &self.serve).await?; + server::startup(crate_config.clone()).await?; Ok(()) } + + pub fn regen_page() {} } diff --git a/src/config.rs b/src/config.rs index 9d38160f2..39a3d2038 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,43 +1,76 @@ use crate::error::Result; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; - +use std::{fs::File, io::Read, path::PathBuf}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DioxusConfig { - application: ApplicationConfig, - web: WebConfig, + pub application: ApplicationConfig, + pub web: WebConfig, +} + +impl DioxusConfig { + pub fn load() -> crate::error::Result { + let crate_dir = crate::cargo::crate_root()?; + + if !crate_dir.join("Dioxus.toml").is_file() { + return Err(crate::error::Error::CargoError( + "Dioxus.toml not found".into(), + )); + } + + let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?; + let mut meta_str = String::new(); + dioxus_conf_file.read_to_string(&mut meta_str)?; + + match toml::from_str::(&meta_str) { + Ok(v) => return Ok(v), + Err(e) => { + log::error!("{}", e); + return Err(crate::error::Error::Unique( + "Dioxus.toml parse failed".into(), + )); + } + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationConfig { - name: String, - platform: Vec, + pub name: String, + pub platforms: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebConfig { - app: WebAppConfing, - watcher: WebWatcherConfing, - resource: WebResourceConfing, + pub app: WebAppConfing, + pub watcher: WebWatcherConfing, + pub resource: WebResourceConfing, } - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfing { - + pub title: Option, + pub out_dir: Option, + pub static_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebWatcherConfing { - + pub watch_path: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebResourceConfing { - + pub dev: WebDevResourceConfing, + pub style: Option>, + pub script: Option>, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebDevResourceConfing { + pub style: Option>, + pub script: Option>, +} #[derive(Debug, Clone)] pub struct CrateConfig { @@ -48,6 +81,7 @@ pub struct CrateConfig { pub static_dir: PathBuf, pub manifest: cargo_toml::Manifest, pub executable: ExecutableType, + pub dioxus_config: DioxusConfig, pub release: bool, } @@ -60,12 +94,23 @@ pub enum ExecutableType { impl CrateConfig { pub fn new() -> Result { + let dioxus_config = DioxusConfig::load()?; + let crate_dir = crate::cargo::crate_root()?; let workspace_dir = crate::cargo::workspace_root()?; let target_dir = workspace_dir.join("target"); - let out_dir = crate_dir.join("public"); + + let out_dir = match dioxus_config.web.app.out_dir { + Some(ref v) => crate_dir.join(v), + None => crate_dir.join("dist"), + }; + let cargo_def = &crate_dir.join("Cargo.toml"); - let static_dir = crate_dir.join("static"); + + let static_dir = match dioxus_config.web.app.static_dir { + Some(ref v) => crate_dir.join(v), + None => crate_dir.join("static"), + }; let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap(); @@ -96,6 +141,7 @@ impl CrateConfig { manifest, executable, release, + dioxus_config, }) } @@ -124,4 +170,4 @@ impl CrateConfig { // self.release = options.release; // self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path(); // } -} \ No newline at end of file +} diff --git a/src/server/err.html b/src/server/err.html deleted file mode 100644 index 8fdbf9bae..000000000 --- a/src/server/err.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -
-

- Sorry, but building your application failed. -

-

- Here's the error: -

- - {err} - -
- - - diff --git a/src/server/mod.rs b/src/server/mod.rs index 6b91a2e71..4d33f524e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -13,7 +13,7 @@ use std::{ }; use tower_http::services::ServeDir; -use crate::{builder, CrateConfig}; +use crate::{builder, crate_root, CrateConfig}; struct WsRelodState { update: bool, @@ -25,42 +25,54 @@ impl WsRelodState { } } -pub async fn startup( - config: CrateConfig, - opts: &crate::cfg::ConfigOptsServe, -) -> anyhow::Result<()> { +pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { log::info!("🚀 Starting development server..."); let (tx, rx) = channel(); - let dist_path = opts.dist.clone().unwrap_or(PathBuf::from("dist")); + let dist_path = config.out_dir.clone(); // file watcher: check file change - let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); + let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); watcher - .watch( - config.crate_dir.join("src").clone(), - notify::RecursiveMode::Recursive, - ) + .watch(config.crate_dir.clone(), notify::RecursiveMode::Recursive) .unwrap(); let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false })); let watcher_conf = config.clone(); let watcher_ws_state = ws_reload_state.clone(); - let watcher_dist_path = dist_path.clone(); tokio::spawn(async move { + let allow_watch_path = watcher_conf + .dioxus_config + .web + .watcher + .watch_path + .clone() + .unwrap_or(vec![PathBuf::from("src")]); + let crate_dir = watcher_conf.crate_dir.clone(); loop { if let Ok(v) = rx.recv() { match v { - DebouncedEvent::Create(_) - | DebouncedEvent::Write(_) - | DebouncedEvent::Remove(_) - | DebouncedEvent::Rename(_, _) => { - if let Ok(_) = builder::build(&watcher_conf, watcher_dist_path.clone()) { - // change the websocket reload state to true; - // the page will auto-reload. - watcher_ws_state.lock().unwrap().change(); + DebouncedEvent::Create(e) + | DebouncedEvent::Write(e) + | DebouncedEvent::Remove(e) + | DebouncedEvent::Rename(e, _) => { + let mut reload = false; + for path in &allow_watch_path { + let temp = crate_dir.clone().join(path); + if e.starts_with(temp) { + reload = true; + break; + } + } + + if reload { + if let Ok(_) = builder::build(&watcher_conf) { + // change the websocket reload state to true; + // the page will auto-reload. + watcher_ws_state.lock().unwrap().change(); + } } } _ => {} @@ -70,7 +82,7 @@ pub async fn startup( }); let app = Router::new() - .route("/ws", get(ws_handler)) + .route("/_dioxus/ws", get(ws_handler)) .fallback( get_service(ServeDir::new(config.crate_dir.join(&dist_path))).handle_error( |error: std::io::Error| async move { diff --git a/src/server/serve.html b/src/server/serve.html deleted file mode 100644 index b5268bd68..000000000 --- a/src/server/serve.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Dioxus-CLI Dev Server - - -
- - - - - - - diff --git a/src/template/config.toml b/src/template/config.toml index 9644babc1..ea1efbd4b 100644 --- a/src/template/config.toml +++ b/src/template/config.toml @@ -1,9 +1,38 @@ -[package] -name = "{project}" -version = "0.1.0" -edition = "2021" +[application] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +# App (Project) Name +name = "{project-name}" -[dependencies] -dioxus = { version = "0.1.7", features = ["web"] } \ No newline at end of file +# Dioxus App Support Platform +# desktop, web, mobile, ssr +platforms = ["web"] + +[web.app] + +# HTML title tag content +title = "dioxus | ⛺" + +# Web `build` & `serve` dist path +out_dir = "dist" + +# resource (static) file folder +static_dir = "static" + +[web.watcher] + +watch_path = ["src"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [] \ No newline at end of file diff --git a/src/template/default.rs b/src/template/default.rs index ac1614fc4..47b4a2c1d 100644 --- a/src/template/default.rs +++ b/src/template/default.rs @@ -8,8 +8,8 @@ fn app(cx: Scope) -> Element { cx.render(rsx! ( div { style: "text-align: center;", - h2 { "🌗🚀 Dioxus" } - p { strong { "Frontend that scales." } } + h1 { "🌗 Dioxus 🚀" } + h3 { "Frontend that scales." } p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." } } )) From 7343af2089ae0ff1f3da6b418d8168651a201832 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 23 Jan 2022 22:50:23 +0800 Subject: [PATCH 027/895] feat: `clean` command --- src/assets/index.html | 4 ++-- src/builder.rs | 30 ++++++++++++++++++------- src/cli/build/mod.rs | 22 +++++++++++++++++- src/cli/clean/mod.rs | 35 +++++++++++++++++++++++++++++ src/cli/mod.rs | 3 +-- src/cli/serve/mod.rs | 17 +++++++++----- src/config.rs | 48 ++++++++++++++++++++++++++++++++-------- src/main.rs | 8 ++++--- src/server/mod.rs | 11 ++++++++- src/template/config.toml | 8 +++++-- 10 files changed, 152 insertions(+), 34 deletions(-) diff --git a/src/assets/index.html b/src/assets/index.html index 12e1e5678..9934e490d 100644 --- a/src/assets/index.html +++ b/src/assets/index.html @@ -10,8 +10,8 @@
{script_include} diff --git a/src/builder.rs b/src/builder.rs index 381ef8b28..0ecde96cd 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -19,7 +19,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { out_dir, crate_dir, target_dir, - static_dir, + public_dir, executable, dioxus_config, .. @@ -56,7 +56,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { } // [2] Establish the output directory structure - let bindgen_outdir = out_dir.join("assets"); + let bindgen_outdir = out_dir.join("assets").join("dioxus"); // [3] Bindgen the final binary for use easy linking let mut bindgen_builder = Bindgen::new(); @@ -87,12 +87,26 @@ pub fn build(config: &CrateConfig) -> Result<()> { .out_name(&dioxus_config.application.name) .generate(&bindgen_outdir)?; - let copy_options = fs_extra::dir::CopyOptions::new(); - if static_dir.is_dir() { - match fs_extra::dir::copy(static_dir, out_dir, ©_options) { - Ok(_) => {} - Err(_e) => { - log::warn!("Error copying dir: {}", _e); + let copy_options = fs_extra::dir::CopyOptions { + overwrite: true, + skip_exist: false, + buffer_size: 64000, + copy_inside: false, + content_only: false, + depth: 0, + }; + if public_dir.is_dir() { + for entry in std::fs::read_dir(&public_dir)? { + let path = entry?.path(); + if path.is_file() { + std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?; + } else { + match fs_extra::dir::copy(&path, out_dir, ©_options) { + Ok(_) => {} + Err(_e) => { + log::warn!("Error copying dir: {}", _e); + } + } } } } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index fc329a305..e24a99822 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,4 +1,6 @@ -use crate::cfg::ConfigOptsBuild; +use std::{io::Write, path::PathBuf}; + +use crate::{cfg::ConfigOptsBuild, gen_page}; use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. @@ -18,6 +20,24 @@ impl Build { crate::builder::build(&crate_config)?; + let temp = gen_page(&crate_config.dioxus_config, false); + + let mut file = std::fs::File::create( + crate_config + .crate_dir + .join( + crate_config + .dioxus_config + .web + .app + .out_dir + .clone() + .unwrap_or(PathBuf::from("dist")), + ) + .join("index.html"), + )?; + file.write_all(temp.as_bytes())?; + Ok(()) } } diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index 1edcd053a..4ab7653d2 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -1,6 +1,41 @@ +use std::{ + fs::remove_dir_all, + path::PathBuf, + process::{Command, Stdio}, +}; + use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, StructOpt)] #[structopt(name = "clean")] pub struct Clean {} + +impl Clean { + pub fn clean(self) -> anyhow::Result<()> { + let crate_config = crate::CrateConfig::new()?; + + let output = Command::new("cargo") + .arg("clean") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output()?; + + if !output.status.success() { + log::error!("Cargo clean failed."); + return Ok(()); + } + + let out_dir = crate_config + .dioxus_config + .web + .app + .out_dir + .unwrap_or(PathBuf::from("dist")); + if crate_config.crate_dir.join(&out_dir).is_dir() { + remove_dir_all(crate_config.crate_dir.join(&out_dir))?; + } + + Ok(()) + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 93cbfef28..6224cea32 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -37,8 +37,7 @@ pub enum Commands { /// Init a new project for Dioxus. Init(init::Init), // /// Clean output artifacts. - // Clean(clean::Clean), - + Clean(clean::Clean), // /// Trunk config controls. // Config(config::Config), } diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 7d580f7fb..19a7f28ff 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,4 +1,4 @@ -use crate::{cfg::ConfigOptsServe, gen_page, server}; +use crate::{cfg::ConfigOptsServe, gen_page, server, CrateConfig}; use std::{io::Write, path::PathBuf}; use structopt::StructOpt; @@ -18,6 +18,16 @@ impl Serve { crate::builder::build(&crate_config).expect("build failed"); + // generate dev-index page + Serve::regen_dev_page(&crate_config)?; + + // start the develop server + server::startup(crate_config.clone()).await?; + + Ok(()) + } + + pub fn regen_dev_page(crate_config: &CrateConfig) -> anyhow::Result<()> { let serve_html = gen_page(&crate_config.dioxus_config, true); let mut file = std::fs::File::create( @@ -36,11 +46,6 @@ impl Serve { )?; file.write_all(serve_html.as_bytes())?; - // start the develop server - server::startup(crate_config.clone()).await?; - Ok(()) } - - pub fn regen_page() {} } diff --git a/src/config.rs b/src/config.rs index 39a3d2038..403ad0e81 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,9 +13,8 @@ impl DioxusConfig { let crate_dir = crate::cargo::crate_root()?; if !crate_dir.join("Dioxus.toml").is_file() { - return Err(crate::error::Error::CargoError( - "Dioxus.toml not found".into(), - )); + log::warn!("Config file: `Dioxus.toml` not found."); + return Ok(Self::default()); } let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?; @@ -34,6 +33,36 @@ impl DioxusConfig { } } +impl Default for DioxusConfig { + fn default() -> Self { + Self { + application: ApplicationConfig { + name: "dioxus".into(), + platforms: vec![String::from("web")], + }, + web: WebConfig { + app: WebAppConfing { + title: Some("dioxus | ⛺".into()), + out_dir: Some(PathBuf::from("dist")), + public_dir: Some(PathBuf::from("public")), + }, + watcher: WebWatcherConfing { + watch_path: Some(vec![PathBuf::from("src")]), + reload_html: Some(false), + }, + resource: WebResourceConfing { + dev: WebDevResourceConfing { + style: Some(vec![]), + script: Some(vec![]), + }, + style: Some(vec![]), + script: Some(vec![]), + }, + }, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationConfig { pub name: String, @@ -51,12 +80,13 @@ pub struct WebConfig { pub struct WebAppConfing { pub title: Option, pub out_dir: Option, - pub static_dir: Option, + pub public_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebWatcherConfing { pub watch_path: Option>, + pub reload_html: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -78,7 +108,7 @@ pub struct CrateConfig { pub crate_dir: PathBuf, pub workspace_dir: PathBuf, pub target_dir: PathBuf, - pub static_dir: PathBuf, + pub public_dir: PathBuf, pub manifest: cargo_toml::Manifest, pub executable: ExecutableType, pub dioxus_config: DioxusConfig, @@ -107,9 +137,9 @@ impl CrateConfig { let cargo_def = &crate_dir.join("Cargo.toml"); - let static_dir = match dioxus_config.web.app.static_dir { + let public_dir = match dioxus_config.web.app.public_dir { Some(ref v) => crate_dir.join(v), - None => crate_dir.join("static"), + None => crate_dir.join("public"), }; let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap(); @@ -124,7 +154,7 @@ impl CrateConfig { (&manifest) .package .as_ref() - .and_then(|pkg| Some(pkg.name.replace("-", "_"))) + .and_then(|pkg| Some(pkg.name.clone())) .clone() }) .expect("No lib found from cargo metadata"); @@ -137,7 +167,7 @@ impl CrateConfig { crate_dir, workspace_dir, target_dir, - static_dir, + public_dir, manifest, executable, release, diff --git a/src/main.rs b/src/main.rs index 69636c6e3..70f92cf95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,11 @@ async fn main() -> Result<()> { } } - // Commands::Clean(_) => { - // // - // } + Commands::Clean(opts) => { + if let Err(e) = opts.clean() { + log::error!("clean error: {}", e); + } + } // Commands::Config(_) => { // // diff --git a/src/server/mod.rs b/src/server/mod.rs index 4d33f524e..3151975d5 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -13,7 +13,7 @@ use std::{ }; use tower_http::services::ServeDir; -use crate::{builder, crate_root, CrateConfig}; +use crate::{builder, serve::Serve, CrateConfig}; struct WsRelodState { update: bool, @@ -71,6 +71,15 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { if let Ok(_) = builder::build(&watcher_conf) { // change the websocket reload state to true; // the page will auto-reload. + if watcher_conf + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&watcher_conf); + } watcher_ws_state.lock().unwrap().change(); } } diff --git a/src/template/config.toml b/src/template/config.toml index ea1efbd4b..44f5baabd 100644 --- a/src/template/config.toml +++ b/src/template/config.toml @@ -15,11 +15,15 @@ title = "dioxus | ⛺" # Web `build` & `serve` dist path out_dir = "dist" -# resource (static) file folder -static_dir = "static" +# resource (public) file folder +public_dir = "public" [web.watcher] +# when watcher trigger, regenerate the `index.html` +reload_html = true + +# which files or dirs will be watcher monitoring watch_path = ["src"] # include `assets` in web platform From bdcc06648b0275404b8626bcae6acf62b8af7af8 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 05:55:40 +0800 Subject: [PATCH 028/895] feat: init use `cargo-generate ` --- Cargo.toml | 3 +- Dioxus.toml | 2 +- src/cli/build/mod.rs | 4 ++ src/cli/cfg.rs | 8 ++++ src/cli/init/mod.rs | 97 ++++++++++++++++++++++------------------ src/cli/serve/mod.rs | 5 +++ src/template/config.toml | 42 ----------------- src/template/default.rs | 16 ------- 8 files changed, 74 insertions(+), 103 deletions(-) delete mode 100644 src/template/config.toml delete mode 100644 src/template/default.rs diff --git a/Cargo.toml b/Cargo.toml index 8bb6fd3ce..68dd3ee56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dioxus-cli" -version = "0.1.1" +version = "0.1.2" authors = ["Jonathan Kelley"] edition = "2018" description = "CLI tool for developing, testing, and publishing Dioxus apps" @@ -28,6 +28,7 @@ structopt = "0.3.25" cargo_metadata = "0.14.1" tokio = { version = "1.15.0", features = ["full"] } atty = "0.2.14" +regex = "1.5.4" axum = { version = "0.4.4", features = ["ws", "headers"] } tower-http = { version = "0.2.0", features = ["fs", "trace"] } diff --git a/Dioxus.toml b/Dioxus.toml index abd2d1ee4..b4ba03f9d 100644 --- a/Dioxus.toml +++ b/Dioxus.toml @@ -13,7 +13,7 @@ platforms = ["web"] out_dir = "dist" # resource (static) file folder -static_dir = "static" +public_dir = "public" [web.watcher] diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index e24a99822..cbf82b339 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -18,6 +18,10 @@ impl Build { // change the relase state. crate_config.with_release(self.build.release); + if self.build.example.is_some() { + crate_config.as_example(self.build.example.unwrap()); + } + crate::builder::build(&crate_config)?; let temp = gen_page(&crate_config.dioxus_config, false); diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index ab68ce4f9..6a27c4890 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -16,6 +16,10 @@ pub struct ConfigOptsBuild { #[serde(default)] pub release: bool, + /// Build a example [default: ""] + #[structopt(long)] + pub example: Option, + /// Optional pattern for the app loader script [default: None] /// /// Patterns should include the sequences `{base}`, `{wasm}`, and `{js}` in order to @@ -62,6 +66,10 @@ pub struct ConfigOptsServe { #[structopt(parse(from_os_str))] pub target: Option, + /// Build a example [default: ""] + #[structopt(long)] + pub example: Option, + /// Build in release mode [default: false] #[structopt(long)] #[serde(default)] diff --git a/src/cli/init/mod.rs b/src/cli/init/mod.rs index 52dcf4c14..a19ee68fd 100644 --- a/src/cli/init/mod.rs +++ b/src/cli/init/mod.rs @@ -1,16 +1,18 @@ use std::{ - fs::{File, OpenOptions}, - io::Write, + fs::File, + io::{Read, Write}, path::PathBuf, process::{Command, Stdio}, }; +use regex::Regex; +use serde::Deserialize; use structopt::StructOpt; -use crate::error::{Error, Result}; +use crate::{error::Result, Error}; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, StructOpt)] +#[derive(Clone, Debug, Default, Deserialize, StructOpt)] #[structopt(name = "init")] pub struct Init { /// Init project name @@ -18,69 +20,73 @@ pub struct Init { name: String, /// Template path - #[structopt(default_value = "default", long)] + #[structopt(default_value = "gh:dioxuslabs/dioxus-template", long)] template: String, + + /// Create a `lib` project, include a `hello-world` example. + #[structopt(long)] + #[serde(default)] + pub lib: bool, } impl Init { pub fn init(self) -> Result<()> { - if self.name.contains(".") { + if Self::name_vaild_check(self.name.clone()) { log::error!("❗Unsupported project name."); return Ok(()); } - log::info!("🔧 Start to init a new project '{}'.", self.name); - let project_path = PathBuf::from(&self.name); - if project_path.join("Cargo.toml").is_file() { - log::warn!("Folder '{}' is initialized.", self.name); - return Ok(()); + if project_path.join("Dioxus.toml").is_file() || project_path.join("Cargo.toml").is_file() { + return Err(Error::Other(anyhow::anyhow!( + "🧨 Folder '{}' is initialized.", + &self.name + ))); } + log::info!("🔧 Start to init a new project '{}'.", self.name); + let output = Command::new("cargo") - .arg("init") - .arg(&format!("./{}", self.name)) - .arg("--bin") + .arg("generate") + .arg("--help") .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output()?; if !output.status.success() { - return Err(Error::CargoError("Cargo init failed".into())); + log::warn!("Tool is not installed: cargo-generate, try to install it."); + let install_output = Command::new("cargo") + .arg("install") + .arg("cargo-generate") + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output()?; + if !install_output.status.success() { + return Err(Error::Other(anyhow::anyhow!( + "Try to install cargo-generate failed." + ))); + } } - // get the template code - let template_str = match self.template { - _ => include_str!("../../template/default.rs"), - }; + let generate_output = Command::new("cargo") + .arg("generate") + .arg(&self.template) + .arg("--name") + .arg(&self.name) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output()?; - let main_rs_file = project_path.join("src").join("main.rs"); - if !main_rs_file.is_file() { - return Err(Error::FailedToWrite); + if !generate_output.status.success() { + return Err(Error::Other(anyhow::anyhow!("Generate project failed."))); } - let mut file = File::create(main_rs_file)?; - file.write_all(&template_str.as_bytes())?; - - let mut file = File::create(project_path.join("Dioxus.toml"))?; - let dioxus_conf = String::from(include_str!("../../template/config.toml")) - .replace("{project-name}", &self.name); - file.write_all(dioxus_conf.as_bytes())?; - - // log::info!("🎯 Project initialization completed."); - - if !Command::new("cargo") - .args(["add", "dioxus", "--features web"]) - .output()? - .status - .success() - { - let mut file = OpenOptions::new() - .append(true) - .open(project_path.join("Cargo.toml"))?; - file.write_all("dioxus = { version = \"0.1.7\", features = [\"web\"] }".as_bytes())?; - } + let mut dioxus_file = File::open(project_path.join("Dioxus.toml"))?; + let mut meta_file = String::new(); + dioxus_file.read_to_string(&mut meta_file)?; + meta_file = meta_file.replace("{{project-name}}", &self.name); + File::create(project_path.join("Dioxus.toml"))?.write_all(meta_file.as_bytes())?; println!(""); log::info!("💡 Project initialized:"); @@ -89,4 +95,9 @@ impl Init { Ok(()) } + + fn name_vaild_check(name: String) -> bool { + let r = Regex::new(r"^[a-zA-Z][a-zA-Z0-9\-_]$").unwrap(); + r.is_match(&name) + } } diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 19a7f28ff..57716ac7e 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -13,9 +13,14 @@ pub struct Serve { impl Serve { pub async fn serve(self) -> anyhow::Result<()> { let mut crate_config = crate::CrateConfig::new()?; + // change the relase state. crate_config.with_release(self.serve.release); + if self.serve.example.is_some() { + crate_config.as_example(self.serve.example.unwrap()); + } + crate::builder::build(&crate_config).expect("build failed"); // generate dev-index page diff --git a/src/template/config.toml b/src/template/config.toml deleted file mode 100644 index 44f5baabd..000000000 --- a/src/template/config.toml +++ /dev/null @@ -1,42 +0,0 @@ -[application] - -# App (Project) Name -name = "{project-name}" - -# Dioxus App Support Platform -# desktop, web, mobile, ssr -platforms = ["web"] - -[web.app] - -# HTML title tag content -title = "dioxus | ⛺" - -# Web `build` & `serve` dist path -out_dir = "dist" - -# resource (public) file folder -public_dir = "public" - -[web.watcher] - -# when watcher trigger, regenerate the `index.html` -reload_html = true - -# which files or dirs will be watcher monitoring -watch_path = ["src"] - -# include `assets` in web platform -[web.resource] - -# CSS style file -style = [] - -# Javascript code file -script = [] - -[web.resource.dev] - -# Javascript code file -# serve: [dev-server] only -script = [] \ No newline at end of file diff --git a/src/template/default.rs b/src/template/default.rs deleted file mode 100644 index 47b4a2c1d..000000000 --- a/src/template/default.rs +++ /dev/null @@ -1,16 +0,0 @@ -use dioxus::prelude::*; - -fn main() { - dioxus::web::launch(app); -} - -fn app(cx: Scope) -> Element { - cx.render(rsx! ( - div { - style: "text-align: center;", - h1 { "🌗 Dioxus 🚀" } - h3 { "Frontend that scales." } - p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." } - } - )) -} From 0ff4881d54f03115812ddeda48fa4687683be8c3 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 08:55:52 +0800 Subject: [PATCH 029/895] feat: support `desktop` build --- src/cli/build/mod.rs | 63 +++++++++++++++++++++++++++++++++++++++++++- src/cli/cfg.rs | 41 +++------------------------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index cbf82b339..82060b436 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,6 +1,7 @@ -use std::{io::Write, path::PathBuf}; +use std::{io::Write, path::PathBuf, process::Command, fs::copy}; use crate::{cfg::ConfigOptsBuild, gen_page}; +use std::fs::remove_dir_all; use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. @@ -22,6 +23,66 @@ impl Build { crate_config.as_example(self.build.example.unwrap()); } + if self.build.platform.is_some() { + if self.build.platform.unwrap().to_uppercase() == "DESKTOP" { + log::info!("🚅 Running build command..."); + + let mut cmd = Command::new("cargo"); + cmd.current_dir(&crate_config.crate_dir) + .arg("build") + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()); + + if self.build.release { + cmd.arg("--release"); + } + + match &crate_config.executable { + crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), + crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), + crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name), + }; + + let output = cmd.output()?; + + if output.status.success() { + if crate_config.out_dir.is_dir() { + + remove_dir_all(&crate_config.out_dir)?; + + let release_type = match crate_config.release { + true => "release", + false => "debug", + }; + + let mut res_path = match &crate_config.executable { + crate::ExecutableType::Binary(name) + | crate::ExecutableType::Lib(name) => crate_config + .target_dir + .join(format!("{}", release_type)) + .join(format!("{}", name)), + + crate::ExecutableType::Example(name) => crate_config + .target_dir + .join(format!("{}/examples", release_type)) + .join(format!("{}", name)), + }; + + let target_file; + if cfg!(windows) { + res_path.set_extension("exe"); + target_file = format!("{}.exe", &crate_config.dioxus_config.application.name); + } else { + target_file = crate_config.dioxus_config.application.name.clone(); + } + copy(res_path, &crate_config.out_dir.join(target_file))?; + } + } + + return Ok(()); + } + } + crate::builder::build(&crate_config)?; let temp = gen_page(&crate_config.dioxus_config, false); diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 6a27c4890..7010d62e6 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -20,44 +20,9 @@ pub struct ConfigOptsBuild { #[structopt(long)] pub example: Option, - /// Optional pattern for the app loader script [default: None] - /// - /// Patterns should include the sequences `{base}`, `{wasm}`, and `{js}` in order to - /// properly load the application. Other sequences may be included corresponding - /// to key/value pairs provided in `pattern_params`. - /// - /// These values can only be provided via config file. - #[structopt(skip)] - #[serde(default)] - pub pattern_script: Option, - - /// Optional pattern for the app preload element [default: None] - /// - /// Patterns should include the sequences `{base}`, `{wasm}`, and `{js}` in order to - /// properly preload the application. Other sequences may be included corresponding - /// to key/value pairs provided in `pattern_params`. - /// - /// These values can only be provided via config file. - #[structopt(skip)] - #[serde(default)] - pub pattern_preload: Option, - - #[structopt(skip)] - #[serde(default)] - /// Optional replacement parameters corresponding to the patterns provided in - /// `pattern_script` and `pattern_preload`. - /// - /// When a pattern is being replaced with its corresponding value from this map, if the value is - /// prefixed with the symbol `@`, then the value is expected to be a file path, and the pattern - /// will be replaced with the contents of the target file. This allows insertion of some big JSON - /// state or even HTML files as a part of the `index.html` build. - /// - /// Trunk will automatically insert the `base`, `wasm` and `js` key/values into this map. In order - //// for the app to be loaded properly, the patterns `{base}`, `{wasm}` and `{js}` should be used - /// in `pattern_script` and `pattern_preload`. - /// - /// These values can only be provided via config file. - pub pattern_params: Option>, + /// Build platform: support Web & Desktop [default: "web"] + #[structopt(long)] + pub platform: Option, } #[derive(Clone, Debug, Default, Deserialize, StructOpt)] From bb69a040456db2e2a669ba4e3d80f2d2da44415f Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 11:29:39 +0800 Subject: [PATCH 030/895] feat: commit code --- Dioxus.toml | 4 +-- src/cli/build/mod.rs | 76 ++++++++++++++++++++++++++++---------------- src/cli/cfg.rs | 1 - src/cli/clean/mod.rs | 3 +- src/cli/serve/mod.rs | 3 +- src/config.rs | 6 ++-- 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/Dioxus.toml b/Dioxus.toml index b4ba03f9d..86f52c349 100644 --- a/Dioxus.toml +++ b/Dioxus.toml @@ -7,11 +7,11 @@ name = "dioxus-cli" # desktop, web, mobile, ssr platforms = ["web"] -[web.app] - # Web `build` & `serve` dist path out_dir = "dist" +[web.app] + # resource (static) file folder public_dir = "public" diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 82060b436..c1639e815 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,4 +1,9 @@ -use std::{io::Write, path::PathBuf, process::Command, fs::copy}; +use std::{ + fs::{copy, create_dir_all}, + io::Write, + path::PathBuf, + process::Command, +}; use crate::{cfg::ConfigOptsBuild, gen_page}; use std::fs::remove_dir_all; @@ -25,7 +30,7 @@ impl Build { if self.build.platform.is_some() { if self.build.platform.unwrap().to_uppercase() == "DESKTOP" { - log::info!("🚅 Running build command..."); + log::info!("🚅 Running build [Desktop] command..."); let mut cmd = Command::new("cargo"); cmd.current_dir(&crate_config.crate_dir) @@ -47,36 +52,52 @@ impl Build { if output.status.success() { if crate_config.out_dir.is_dir() { - remove_dir_all(&crate_config.out_dir)?; + } - let release_type = match crate_config.release { - true => "release", - false => "debug", - }; - - let mut res_path = match &crate_config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) => crate_config + let release_type = match crate_config.release { + true => "release", + false => "debug", + }; + + let file_name: String; + let mut res_path = match &crate_config.executable { + crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { + file_name = name.clone(); + crate_config .target_dir .join(format!("{}", release_type)) - .join(format!("{}", name)), - - crate::ExecutableType::Example(name) => crate_config - .target_dir - .join(format!("{}/examples", release_type)) - .join(format!("{}", name)), - }; - - let target_file; - if cfg!(windows) { - res_path.set_extension("exe"); - target_file = format!("{}.exe", &crate_config.dioxus_config.application.name); - } else { - target_file = crate_config.dioxus_config.application.name.clone(); + .join(format!("{}", name)) } - copy(res_path, &crate_config.out_dir.join(target_file))?; + crate::ExecutableType::Example(name) => { + file_name = name.clone(); + crate_config + .target_dir + .join(format!("{}", release_type)) + .join("examples") + .join(format!("{}", name)) + } + }; + + let target_file; + if cfg!(windows) { + res_path.set_extension("exe"); + target_file = format!("{}.exe", &file_name); + } else { + target_file = file_name.clone(); } + create_dir_all(&crate_config.out_dir)?; + copy(res_path, &crate_config.out_dir.join(target_file))?; + + log::info!( + "🏛 Build completed: [:{}]", + &crate_config + .dioxus_config + .application + .out_dir + .unwrap_or(PathBuf::from("dist")) + .display() + ); } return Ok(()); @@ -93,8 +114,7 @@ impl Build { .join( crate_config .dioxus_config - .web - .app + .application .out_dir .clone() .unwrap_or(PathBuf::from("dist")), diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 7010d62e6..0734f362d 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -2,7 +2,6 @@ use std::path::PathBuf; use structopt::StructOpt; use serde::Deserialize; -use std::collections::HashMap; /// Config options for the build system. #[derive(Clone, Debug, Default, Deserialize, StructOpt)] diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index 4ab7653d2..7ba33b530 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -28,8 +28,7 @@ impl Clean { let out_dir = crate_config .dioxus_config - .web - .app + .application .out_dir .unwrap_or(PathBuf::from("dist")); if crate_config.crate_dir.join(&out_dir).is_dir() { diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 57716ac7e..8b002e1fb 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -41,8 +41,7 @@ impl Serve { .join( crate_config .dioxus_config - .web - .app + .application .out_dir .clone() .unwrap_or(PathBuf::from("dist")), diff --git a/src/config.rs b/src/config.rs index 403ad0e81..ad1e25ea5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -39,11 +39,11 @@ impl Default for DioxusConfig { application: ApplicationConfig { name: "dioxus".into(), platforms: vec![String::from("web")], + out_dir: Some(PathBuf::from("dist")), }, web: WebConfig { app: WebAppConfing { title: Some("dioxus | ⛺".into()), - out_dir: Some(PathBuf::from("dist")), public_dir: Some(PathBuf::from("public")), }, watcher: WebWatcherConfing { @@ -67,6 +67,7 @@ impl Default for DioxusConfig { pub struct ApplicationConfig { pub name: String, pub platforms: Vec, + pub out_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -79,7 +80,6 @@ pub struct WebConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfing { pub title: Option, - pub out_dir: Option, pub public_dir: Option, } @@ -130,7 +130,7 @@ impl CrateConfig { let workspace_dir = crate::cargo::workspace_root()?; let target_dir = workspace_dir.join("target"); - let out_dir = match dioxus_config.web.app.out_dir { + let out_dir = match dioxus_config.application.out_dir { Some(ref v) => crate_dir.join(v), None => crate_dir.join("dist"), }; From d6957774026620c8649e92202e312432580c771c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 11:55:27 +0800 Subject: [PATCH 031/895] feat: support `desktop` --- src/builder.rs | 81 +++++++++++++++++++++++++++++++++++++++++++- src/cli/build/mod.rs | 80 ++----------------------------------------- src/cli/cfg.rs | 4 +++ src/cli/serve/mod.rs | 25 +++++++++++++- 4 files changed, 110 insertions(+), 80 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 0ecde96cd..415e56480 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -3,7 +3,11 @@ use crate::{ error::{Error, Result}, DioxusConfig, }; -use std::process::Command; +use std::{ + fs::{copy, create_dir_all, remove_dir_all}, + path::PathBuf, + process::Command, +}; use wasm_bindgen_cli_support::Bindgen; pub fn build(config: &CrateConfig) -> Result<()> { @@ -116,6 +120,81 @@ pub fn build(config: &CrateConfig) -> Result<()> { Ok(()) } +pub fn build_desktop(config: &CrateConfig) -> Result<()> { + log::info!("🚅 Running build [Desktop] command..."); + + let mut cmd = Command::new("cargo"); + cmd.current_dir(&config.crate_dir) + .arg("build") + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()); + + if config.release { + cmd.arg("--release"); + } + + match &config.executable { + crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), + crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), + crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name), + }; + + let output = cmd.output()?; + + if output.status.success() { + if config.out_dir.is_dir() { + remove_dir_all(&config.out_dir)?; + } + + let release_type = match config.release { + true => "release", + false => "debug", + }; + + let file_name: String; + let mut res_path = match &config.executable { + crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { + file_name = name.clone(); + config + .target_dir + .join(format!("{}", release_type)) + .join(format!("{}", name)) + } + crate::ExecutableType::Example(name) => { + file_name = name.clone(); + config + .target_dir + .join(format!("{}", release_type)) + .join("examples") + .join(format!("{}", name)) + } + }; + + let target_file; + if cfg!(windows) { + res_path.set_extension("exe"); + target_file = format!("{}.exe", &file_name); + } else { + target_file = file_name.clone(); + } + create_dir_all(&config.out_dir)?; + copy(res_path, &config.out_dir.join(target_file))?; + + log::info!( + "🚩 Build completed: [./{}]", + config + .dioxus_config + .application + .out_dir + .clone() + .unwrap_or(PathBuf::from("dist")) + .display() + ); + } + + Ok(()) +} + pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let mut html = String::from(include_str!("./assets/index.html")); diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index c1639e815..f018165ef 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,12 +1,6 @@ -use std::{ - fs::{copy, create_dir_all}, - io::Write, - path::PathBuf, - process::Command, -}; +use std::{io::Write, path::PathBuf}; use crate::{cfg::ConfigOptsBuild, gen_page}; -use std::fs::remove_dir_all; use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. @@ -30,77 +24,7 @@ impl Build { if self.build.platform.is_some() { if self.build.platform.unwrap().to_uppercase() == "DESKTOP" { - log::info!("🚅 Running build [Desktop] command..."); - - let mut cmd = Command::new("cargo"); - cmd.current_dir(&crate_config.crate_dir) - .arg("build") - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()); - - if self.build.release { - cmd.arg("--release"); - } - - match &crate_config.executable { - crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), - crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), - crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name), - }; - - let output = cmd.output()?; - - if output.status.success() { - if crate_config.out_dir.is_dir() { - remove_dir_all(&crate_config.out_dir)?; - } - - let release_type = match crate_config.release { - true => "release", - false => "debug", - }; - - let file_name: String; - let mut res_path = match &crate_config.executable { - crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => { - file_name = name.clone(); - crate_config - .target_dir - .join(format!("{}", release_type)) - .join(format!("{}", name)) - } - crate::ExecutableType::Example(name) => { - file_name = name.clone(); - crate_config - .target_dir - .join(format!("{}", release_type)) - .join("examples") - .join(format!("{}", name)) - } - }; - - let target_file; - if cfg!(windows) { - res_path.set_extension("exe"); - target_file = format!("{}.exe", &file_name); - } else { - target_file = file_name.clone(); - } - create_dir_all(&crate_config.out_dir)?; - copy(res_path, &crate_config.out_dir.join(target_file))?; - - log::info!( - "🏛 Build completed: [:{}]", - &crate_config - .dioxus_config - .application - .out_dir - .unwrap_or(PathBuf::from("dist")) - .display() - ); - } - - return Ok(()); + crate::builder::build_desktop(&crate_config)?; } } diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 0734f362d..454da71fe 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -38,6 +38,10 @@ pub struct ConfigOptsServe { #[structopt(long)] #[serde(default)] pub release: bool, + + /// Build platform: support Web & Desktop [default: "web"] + #[structopt(long)] + pub platform: Option, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 8b002e1fb..ef413a63e 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,5 +1,5 @@ use crate::{cfg::ConfigOptsServe, gen_page, server, CrateConfig}; -use std::{io::Write, path::PathBuf}; +use std::{io::Write, path::PathBuf, process::Command}; use structopt::StructOpt; /// Run the WASM project on dev-server @@ -21,6 +21,29 @@ impl Serve { crate_config.as_example(self.serve.example.unwrap()); } + if self.serve.platform.is_some() { + if self.serve.platform.unwrap().to_uppercase() == "DESKTOP" { + crate::builder::build_desktop(&crate_config)?; + + match &crate_config.executable { + crate::ExecutableType::Binary(name) + | crate::ExecutableType::Lib(name) + | crate::ExecutableType::Example(name) => { + let mut file = crate_config.out_dir.join(name); + if cfg!(windows) { + file.set_extension("exe"); + } + Command::new(format!( + "{}", + crate_config.out_dir.join(file).to_str().unwrap() + )) + .output()?; + } + } + return Ok(()); + } + } + crate::builder::build(&crate_config).expect("build failed"); // generate dev-index page From 4cc7752adf17e41e153bcfa490ea14964e67b863 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 12:16:02 +0800 Subject: [PATCH 032/895] fix: change `init` to `create` --- src/cli/{init => create}/mod.rs | 10 +++++----- src/cli/mod.rs | 4 ++-- src/config.rs | 3 +-- src/main.rs | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) rename src/cli/{init => create}/mod.rs (94%) diff --git a/src/cli/init/mod.rs b/src/cli/create/mod.rs similarity index 94% rename from src/cli/init/mod.rs rename to src/cli/create/mod.rs index a19ee68fd..7cb2edbbe 100644 --- a/src/cli/init/mod.rs +++ b/src/cli/create/mod.rs @@ -13,8 +13,8 @@ use crate::{error::Result, Error}; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Default, Deserialize, StructOpt)] -#[structopt(name = "init")] -pub struct Init { +#[structopt(name = "create")] +pub struct Create { /// Init project name #[structopt(default_value = ".")] name: String, @@ -29,8 +29,8 @@ pub struct Init { pub lib: bool, } -impl Init { - pub fn init(self) -> Result<()> { +impl Create { + pub fn create(self) -> Result<()> { if Self::name_vaild_check(self.name.clone()) { log::error!("❗Unsupported project name."); return Ok(()); @@ -45,7 +45,7 @@ impl Init { ))); } - log::info!("🔧 Start to init a new project '{}'.", self.name); + log::info!("🔧 Start to create a new project '{}'.", self.name); let output = Command::new("cargo") .arg("generate") diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6224cea32..91d561463 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -3,7 +3,7 @@ use structopt::StructOpt; pub mod build; pub mod cfg; pub mod clean; -pub mod init; +pub mod create; pub mod serve; pub mod translate; @@ -35,7 +35,7 @@ pub enum Commands { /// Build, watch & serve the Rust WASM app and all of its assets. Serve(serve::Serve), /// Init a new project for Dioxus. - Init(init::Init), + Create(create::Create), // /// Clean output artifacts. Clean(clean::Clean), // /// Trunk config controls. diff --git a/src/config.rs b/src/config.rs index ad1e25ea5..fa52ddcbc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,8 +13,7 @@ impl DioxusConfig { let crate_dir = crate::cargo::crate_root()?; if !crate_dir.join("Dioxus.toml").is_file() { - log::warn!("Config file: `Dioxus.toml` not found."); - return Ok(Self::default()); + return Err(crate::error::Error::Unique("Config file: `Dioxus.toml` not found.".into())); } let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?; diff --git a/src/main.rs b/src/main.rs index 70f92cf95..20536048b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,9 +34,9 @@ async fn main() -> Result<()> { } } - Commands::Init(opts) => { - if let Err(e) = opts.init() { - log::error!("init error: {}", e); + Commands::Create(opts) => { + if let Err(e) = opts.create() { + log::error!("create error: {}", e); } } } From 66b832045ad436c4577990ef138407331d38d056 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 24 Jan 2022 16:18:16 +0800 Subject: [PATCH 033/895] feat: add `config` command --- Dioxus.toml => src/assets/dioxus.toml | 18 +++++------ src/cli/config/mod.rs | 43 +++++++++++++++++++++++++++ src/cli/create/mod.rs | 5 ---- src/cli/mod.rs | 7 +++-- src/config.rs | 4 ++- src/main.rs | 6 ++++ 6 files changed, 63 insertions(+), 20 deletions(-) rename Dioxus.toml => src/assets/dioxus.toml (79%) create mode 100644 src/cli/config/mod.rs diff --git a/Dioxus.toml b/src/assets/dioxus.toml similarity index 79% rename from Dioxus.toml rename to src/assets/dioxus.toml index 86f52c349..717b070e2 100644 --- a/Dioxus.toml +++ b/src/assets/dioxus.toml @@ -1,7 +1,7 @@ [application] # App (Project) Name -name = "dioxus-cli" +name = "{{project-name}}" # Dioxus App Support Platform # desktop, web, mobile, ssr @@ -12,31 +12,27 @@ out_dir = "dist" [web.app] +# HTML title tag content +title = "dioxus | ⛺" + # resource (static) file folder public_dir = "public" [web.watcher] - watch_path = ["src"] # include `assets` in web platform [web.resource] # CSS style file -style = [ - "./my-style.css" -] +style = [] # Javascript code file -script = [ - "./app.js" -] +script = [] [web.resource.dev] # Javascript code file # serve: [dev-server] only -script = [ - "./debug.js" -] \ No newline at end of file +script = [] \ No newline at end of file diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs new file mode 100644 index 000000000..5e903dc3a --- /dev/null +++ b/src/cli/config/mod.rs @@ -0,0 +1,43 @@ +use std::{fs::File, io::Write}; + +use serde::Deserialize; +use structopt::StructOpt; + +/// Build the Rust WASM app and all of its assets. +#[derive(Clone, Debug, Deserialize, StructOpt)] +#[structopt(name = "config")] +pub enum Config { + /// Init `Dioxus.toml` for project/folder. + Init { + /// Init project name + name: String, + + /// Cover old config + #[structopt(long)] + #[serde(default)] + force: bool, + }, +} + +impl Config { + pub fn config(self) -> anyhow::Result<()> { + let crate_root = crate::cargo::crate_root()?; + match self { + Config::Init { name, force } => { + let conf_path = crate_root.join("Dioxus.toml"); + if conf_path.is_file() && force == false { + log::warn!( + "config file `Dioxus.toml` already exist, use `--force` to overwrite it." + ); + return Ok(()); + } + let mut file = File::create(conf_path)?; + let content = String::from(include_str!("../../assets/dioxus.toml")) + .replace("{{project-name}}", &name); + file.write_all(content.as_bytes())?; + log::info!("🚩 Init config file completed."); + } + } + Ok(()) + } +} diff --git a/src/cli/create/mod.rs b/src/cli/create/mod.rs index 7cb2edbbe..42364ddab 100644 --- a/src/cli/create/mod.rs +++ b/src/cli/create/mod.rs @@ -22,11 +22,6 @@ pub struct Create { /// Template path #[structopt(default_value = "gh:dioxuslabs/dioxus-template", long)] template: String, - - /// Create a `lib` project, include a `hello-world` example. - #[structopt(long)] - #[serde(default)] - pub lib: bool, } impl Create { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 91d561463..4a72e00ac 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -3,6 +3,7 @@ use structopt::StructOpt; pub mod build; pub mod cfg; pub mod clean; +pub mod config; pub mod create; pub mod serve; pub mod translate; @@ -36,8 +37,8 @@ pub enum Commands { Serve(serve::Serve), /// Init a new project for Dioxus. Create(create::Create), - // /// Clean output artifacts. + /// Clean output artifacts. Clean(clean::Clean), - // /// Trunk config controls. - // Config(config::Config), + /// Dioxus config file controls. + Config(config::Config), } diff --git a/src/config.rs b/src/config.rs index fa52ddcbc..fb26b50bf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,7 +13,9 @@ impl DioxusConfig { let crate_dir = crate::cargo::crate_root()?; if !crate_dir.join("Dioxus.toml").is_file() { - return Err(crate::error::Error::Unique("Config file: `Dioxus.toml` not found.".into())); + return Err(crate::error::Error::Unique( + "Config file: `Dioxus.toml` not found.".into(), + )); } let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?; diff --git a/src/main.rs b/src/main.rs index 20536048b..1ef3a08f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,12 @@ async fn main() -> Result<()> { log::error!("create error: {}", e); } } + + Commands::Config(opts) => { + if let Err(e) = opts.config() { + log::error!("config error: {}", e); + } + } } Ok(()) From 84d1867654482640fa2cf31dd3eae10bf1bfa52d Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 25 Jan 2022 12:42:27 +0800 Subject: [PATCH 034/895] fix: use clippy fix --- src/builder.rs | 18 +++++++++--------- src/cli/build/mod.rs | 6 ++---- src/cli/config/mod.rs | 2 +- src/cli/create/mod.rs | 2 +- src/cli/serve/mod.rs | 29 ++++++++++++----------------- src/cli/translate/mod.rs | 4 ++-- src/cli/translate/to_component.rs | 2 +- src/config.rs | 15 +++++++-------- src/logging.rs | 2 +- 9 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 415e56480..c281f2b80 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -157,16 +157,16 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { file_name = name.clone(); config .target_dir - .join(format!("{}", release_type)) - .join(format!("{}", name)) + .join(release_type.to_string()) + .join(name.to_string()) } crate::ExecutableType::Example(name) => { file_name = name.clone(); config .target_dir - .join(format!("{}", release_type)) + .join(release_type.to_string()) .join("examples") - .join(format!("{}", name)) + .join(name.to_string()) } }; @@ -175,7 +175,7 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { res_path.set_extension("exe"); target_file = format!("{}.exe", &file_name); } else { - target_file = file_name.clone(); + target_file = file_name; } create_dir_all(&config.out_dir)?; copy(res_path, &config.out_dir.join(target_file))?; @@ -200,12 +200,12 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let resouces = config.web.resource.clone(); - let mut style_list = resouces.style.unwrap_or(vec![]); - let mut script_list = resouces.script.unwrap_or(vec![]); + let mut style_list = resouces.style.unwrap_or_default(); + let mut script_list = resouces.script.unwrap_or_default(); if serve { - let mut dev_style = resouces.dev.style.clone().unwrap_or(vec![]); - let mut dev_script = resouces.dev.script.clone().unwrap_or(vec![]); + let mut dev_style = resouces.dev.style.clone().unwrap_or_default(); + let mut dev_script = resouces.dev.script.unwrap_or_default(); style_list.append(&mut dev_style); script_list.append(&mut dev_script); } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index f018165ef..318f6b7f5 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -22,10 +22,8 @@ impl Build { crate_config.as_example(self.build.example.unwrap()); } - if self.build.platform.is_some() { - if self.build.platform.unwrap().to_uppercase() == "DESKTOP" { - crate::builder::build_desktop(&crate_config)?; - } + if self.build.platform.is_some() && self.build.platform.unwrap().to_uppercase() == "DESKTOP" { + crate::builder::build_desktop(&crate_config)?; } crate::builder::build(&crate_config)?; diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 5e903dc3a..d5291a7d6 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -25,7 +25,7 @@ impl Config { match self { Config::Init { name, force } => { let conf_path = crate_root.join("Dioxus.toml"); - if conf_path.is_file() && force == false { + if conf_path.is_file() && !force { log::warn!( "config file `Dioxus.toml` already exist, use `--force` to overwrite it." ); diff --git a/src/cli/create/mod.rs b/src/cli/create/mod.rs index 42364ddab..fa553c55a 100644 --- a/src/cli/create/mod.rs +++ b/src/cli/create/mod.rs @@ -83,7 +83,7 @@ impl Create { meta_file = meta_file.replace("{{project-name}}", &self.name); File::create(project_path.join("Dioxus.toml"))?.write_all(meta_file.as_bytes())?; - println!(""); + println!(); log::info!("💡 Project initialized:"); log::info!("🎯> cd ./{}", self.name); log::info!("🎯> dioxus serve"); diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index ef413a63e..04795ab13 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -21,27 +21,22 @@ impl Serve { crate_config.as_example(self.serve.example.unwrap()); } - if self.serve.platform.is_some() { - if self.serve.platform.unwrap().to_uppercase() == "DESKTOP" { - crate::builder::build_desktop(&crate_config)?; + if self.serve.platform.is_some() && self.serve.platform.unwrap().to_uppercase() == "DESKTOP" { + crate::builder::build_desktop(&crate_config)?; - match &crate_config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) - | crate::ExecutableType::Example(name) => { - let mut file = crate_config.out_dir.join(name); - if cfg!(windows) { - file.set_extension("exe"); - } - Command::new(format!( - "{}", - crate_config.out_dir.join(file).to_str().unwrap() - )) - .output()?; + match &crate_config.executable { + crate::ExecutableType::Binary(name) + | crate::ExecutableType::Lib(name) + | crate::ExecutableType::Example(name) => { + let mut file = crate_config.out_dir.join(name); + if cfg!(windows) { + file.set_extension("exe"); } + Command::new(crate_config.out_dir.join(file).to_str().unwrap().to_string()) + .output()?; } - return Ok(()); } + return Ok(()); } crate::builder::build(&crate_config).expect("build failed"); diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index 5799cad02..a62a1b4b3 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -48,7 +48,7 @@ impl Translate { exit(0); }) }); - if let None = temp { + if temp.is_none() { if let Some(s) = source { contents = s; } else { @@ -112,7 +112,7 @@ fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result { } write!(f, "\",")?; } - write!(f, "\n")?; + writeln!(f)?; // write the attributes if let Some(id) = &el.id { diff --git a/src/cli/translate/to_component.rs b/src/cli/translate/to_component.rs index 972da7a25..c83777ccb 100644 --- a/src/cli/translate/to_component.rs +++ b/src/cli/translate/to_component.rs @@ -120,7 +120,7 @@ fn render_element<'a>( } write!(f, "\",")?; } - write!(f, "\n")?; + writeln!(f)?; // write the attributes if let Some(id) = &el.id { diff --git a/src/config.rs b/src/config.rs index fb26b50bf..fa7e1bd1c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,12 +23,12 @@ impl DioxusConfig { dioxus_conf_file.read_to_string(&mut meta_str)?; match toml::from_str::(&meta_str) { - Ok(v) => return Ok(v), + Ok(v) => Ok(v), Err(e) => { log::error!("{}", e); - return Err(crate::error::Error::Unique( + Err(crate::error::Error::Unique( "Dioxus.toml parse failed".into(), - )); + )) } } } @@ -147,16 +147,15 @@ impl CrateConfig { // We just assume they're using a 'main.rs' // Anyway, we've already parsed the manifest, so it should be easy to change the type - let output_filename = (&manifest) + let output_filename = manifest .lib .as_ref() .and_then(|lib| lib.name.clone()) .or_else(|| { - (&manifest) + manifest .package - .as_ref() - .and_then(|pkg| Some(pkg.name.clone())) - .clone() + .as_ref().map(|pkg| pkg.name.clone()) + }) .expect("No lib found from cargo metadata"); let executable = ExecutableType::Binary(output_filename); diff --git a/src/logging.rs b/src/logging.rs index d30eeee47..48c2a2788 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -14,7 +14,7 @@ pub fn set_up_logging() { // configure colors for the name of the level. // since almost all of them are the same as the color for the whole line, we // just clone `colors_line` and overwrite our changes - let colors_level = colors_line.clone().info(Color::Green); + let colors_level = colors_line.info(Color::Green); // here we set up our fern Dispatch fern::Dispatch::new() .format(move |out, message, record| { From 1c2cf3330ee164a9492342ab1132f8d17b15931b Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 25 Jan 2022 13:52:33 +0800 Subject: [PATCH 035/895] fix: use clippy fix --- src/builder.rs | 4 ++-- src/cargo.rs | 6 +++--- src/cli/build/mod.rs | 2 +- src/cli/clean/mod.rs | 2 +- src/cli/serve/mod.rs | 2 +- src/cli/translate/mod.rs | 2 +- src/server/mod.rs | 28 +++++++++++++--------------- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index c281f2b80..7d76f75cc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -187,7 +187,7 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { .application .out_dir .clone() - .unwrap_or(PathBuf::from("dist")) + .unwrap_or_else(|| PathBuf::from("dist")) .display() ); } @@ -238,7 +238,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { html = html.replace("{app_name}", &config.application.name); - let title = config.web.app.title.clone().unwrap_or("dioxus | ⛺".into()); + let title = config.web.app.title.clone().unwrap_or_else(|| "dioxus | ⛺".into()); html.replace("{app_title}", &title) } diff --git a/src/cargo.rs b/src/cargo.rs index 3a911a81e..c268c5a3a 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,6 +1,6 @@ //! Utilities for working with cargo and rust files use crate::error::{Error, Result}; -use std::{env, fs, path::PathBuf, process::Command, str}; +use std::{env, fs, path::{PathBuf, Path}, process::Command, str}; /// How many parent folders are searched for a `Cargo.toml` const MAX_ANCESTORS: u32 = 10; @@ -44,7 +44,7 @@ pub fn workspace_root() -> Result { } let stdout = str::from_utf8(&output.stdout).unwrap(); - for line in stdout.lines() { + if let Some(line) = stdout.lines().next() { let meta: serde_json::Value = serde_json::from_str(line) .map_err(|_| Error::CargoError("InvalidOutput".to_string()))?; @@ -58,7 +58,7 @@ pub fn workspace_root() -> Result { } /// Checks if the directory contains `Cargo.toml` -fn contains_manifest(path: &PathBuf) -> bool { +fn contains_manifest(path: &Path) -> bool { fs::read_dir(path) .map(|entries| { entries diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 318f6b7f5..27015420b 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -39,7 +39,7 @@ impl Build { .application .out_dir .clone() - .unwrap_or(PathBuf::from("dist")), + .unwrap_or_else(|| PathBuf::from("dist")), ) .join("index.html"), )?; diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index 7ba33b530..62593b1ee 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -30,7 +30,7 @@ impl Clean { .dioxus_config .application .out_dir - .unwrap_or(PathBuf::from("dist")); + .unwrap_or_else(|| PathBuf::from("dist")); if crate_config.crate_dir.join(&out_dir).is_dir() { remove_dir_all(crate_config.crate_dir.join(&out_dir))?; } diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 04795ab13..a84d8136d 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -62,7 +62,7 @@ impl Serve { .application .out_dir .clone() - .unwrap_or(PathBuf::from("dist")), + .unwrap_or_else(|| PathBuf::from("dist")), ) .join("index.html"), )?; diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index a62a1b4b3..81b5092ed 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -48,7 +48,7 @@ impl Translate { exit(0); }) }); - if temp.is_none() { + if let Some(..) = temp { if let Some(s) = source { contents = s; } else { diff --git a/src/server/mod.rs b/src/server/mod.rs index 3151975d5..3092a01ec 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -49,7 +49,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { .watcher .watch_path .clone() - .unwrap_or(vec![PathBuf::from("src")]); + .unwrap_or_else(|| vec![PathBuf::from("src")]); let crate_dir = watcher_conf.crate_dir.clone(); loop { if let Ok(v) = rx.recv() { @@ -67,21 +67,19 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { } } - if reload { - if let Ok(_) = builder::build(&watcher_conf) { - // change the websocket reload state to true; - // the page will auto-reload. - if watcher_conf - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&watcher_conf); - } - watcher_ws_state.lock().unwrap().change(); + if reload && builder::build(&watcher_conf).is_ok() { + // change the websocket reload state to true; + // the page will auto-reload. + if watcher_conf + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&watcher_conf); } + watcher_ws_state.lock().unwrap().change(); } } _ => {} From 25e3ee848cadcd14ff291b39436266857037a11a Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 25 Jan 2022 17:09:06 +0800 Subject: [PATCH 036/895] fix: high CPU usage --- src/server/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/mod.rs b/src/server/mod.rs index 3092a01ec..364b7c572 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -118,6 +118,7 @@ async fn ws_handler( ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { loop { + tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; if state.lock().unwrap().update { socket .send(Message::Text(String::from("reload"))) From b01b3f519f5a2a279cb60c479e7000d9819fed33 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 25 Jan 2022 17:51:36 +0800 Subject: [PATCH 037/895] fix: commit code --- src/builder.rs | 17 ++++++++++------ src/cargo.rs | 7 ++++++- src/cli/build/mod.rs | 14 +++++++++---- src/cli/cfg.rs | 8 ++++---- src/cli/serve/mod.rs | 47 ++++++++++++++++++++++++++++---------------- src/config.rs | 12 +++-------- src/main.rs | 3 --- src/server/mod.rs | 6 +++--- 8 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 7d76f75cc..583c9bc8f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -170,13 +170,13 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { } }; - let target_file; - if cfg!(windows) { + let target_file = if cfg!(windows) { res_path.set_extension("exe"); - target_file = format!("{}.exe", &file_name); + format!("{}.exe", &file_name) } else { - target_file = file_name; - } + file_name + }; + create_dir_all(&config.out_dir)?; copy(res_path, &config.out_dir.join(target_file))?; @@ -238,7 +238,12 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { html = html.replace("{app_name}", &config.application.name); - let title = config.web.app.title.clone().unwrap_or_else(|| "dioxus | ⛺".into()); + let title = config + .web + .app + .title + .clone() + .unwrap_or_else(|| "dioxus | ⛺".into()); html.replace("{app_title}", &title) } diff --git a/src/cargo.rs b/src/cargo.rs index c268c5a3a..67a3e48f1 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,6 +1,11 @@ //! Utilities for working with cargo and rust files use crate::error::{Error, Result}; -use std::{env, fs, path::{PathBuf, Path}, process::Command, str}; +use std::{ + env, fs, + path::{Path, PathBuf}, + process::Command, + str, +}; /// How many parent folders are searched for a `Cargo.toml` const MAX_ANCESTORS: u32 = 10; diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 27015420b..684cec58c 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -22,12 +22,18 @@ impl Build { crate_config.as_example(self.build.example.unwrap()); } - if self.build.platform.is_some() && self.build.platform.unwrap().to_uppercase() == "DESKTOP" { - crate::builder::build_desktop(&crate_config)?; + match self.build.platform.as_str() { + "web" => { + crate::builder::build(&crate_config)?; + } + "desktop" => { + crate::builder::build_desktop(&crate_config)?; + } + _ => { + return Err(anyhow::anyhow!("Unsoppurt platform target.")); + } } - crate::builder::build(&crate_config)?; - let temp = gen_page(&crate_config.dioxus_config, false); let mut file = std::fs::File::create( diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 454da71fe..ece00e07e 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -20,8 +20,8 @@ pub struct ConfigOptsBuild { pub example: Option, /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long)] - pub platform: Option, + #[structopt(long, default_value = "web")] + pub platform: String, } #[derive(Clone, Debug, Default, Deserialize, StructOpt)] @@ -40,8 +40,8 @@ pub struct ConfigOptsServe { pub release: bool, /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long)] - pub platform: Option, + #[structopt(long, default_value = "web")] + pub platform: String, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index a84d8136d..fd8f3c4f5 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -21,25 +21,38 @@ impl Serve { crate_config.as_example(self.serve.example.unwrap()); } - if self.serve.platform.is_some() && self.serve.platform.unwrap().to_uppercase() == "DESKTOP" { - crate::builder::build_desktop(&crate_config)?; - - match &crate_config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) - | crate::ExecutableType::Example(name) => { - let mut file = crate_config.out_dir.join(name); - if cfg!(windows) { - file.set_extension("exe"); - } - Command::new(crate_config.out_dir.join(file).to_str().unwrap().to_string()) - .output()?; - } + match self.serve.platform.as_str() { + "web" => { + crate::builder::build(&crate_config)?; } - return Ok(()); - } + "desktop" => { + crate::builder::build_desktop(&crate_config)?; - crate::builder::build(&crate_config).expect("build failed"); + match &crate_config.executable { + crate::ExecutableType::Binary(name) + | crate::ExecutableType::Lib(name) + | crate::ExecutableType::Example(name) => { + let mut file = crate_config.out_dir.join(name); + if cfg!(windows) { + file.set_extension("exe"); + } + Command::new( + crate_config + .out_dir + .join(file) + .to_str() + .unwrap() + .to_string(), + ) + .output()?; + } + } + return Ok(()); + } + _ => { + return Err(anyhow::anyhow!("Unsoppurt platform target.")); + } + } // generate dev-index page Serve::regen_dev_page(&crate_config)?; diff --git a/src/config.rs b/src/config.rs index fa7e1bd1c..088955910 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,9 +13,8 @@ impl DioxusConfig { let crate_dir = crate::cargo::crate_root()?; if !crate_dir.join("Dioxus.toml").is_file() { - return Err(crate::error::Error::Unique( - "Config file: `Dioxus.toml` not found.".into(), - )); + log::warn!("Config file: `Dioxus.toml` not found; using default config."); + return Ok(DioxusConfig::default()); } let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?; @@ -151,12 +150,7 @@ impl CrateConfig { .lib .as_ref() .and_then(|lib| lib.name.clone()) - .or_else(|| { - manifest - .package - .as_ref().map(|pkg| pkg.name.clone()) - - }) + .or_else(|| manifest.package.as_ref().map(|pkg| pkg.name.clone())) .expect("No lib found from cargo metadata"); let executable = ExecutableType::Binary(output_filename); diff --git a/src/main.rs b/src/main.rs index 1ef3a08f1..6b8c177db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,9 +25,6 @@ async fn main() -> Result<()> { } } - // Commands::Config(_) => { - // // - // } Commands::Serve(opts) => { if let Err(e) = opts.serve().await { log::error!("serve error: {}", e); diff --git a/src/server/mod.rs b/src/server/mod.rs index 364b7c572..c7c9074ed 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -58,16 +58,16 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { | DebouncedEvent::Write(e) | DebouncedEvent::Remove(e) | DebouncedEvent::Rename(e, _) => { - let mut reload = false; + let mut should_reload = false; for path in &allow_watch_path { let temp = crate_dir.clone().join(path); if e.starts_with(temp) { - reload = true; + should_reload = true; break; } } - if reload && builder::build(&watcher_conf).is_ok() { + if should_reload && builder::build(&watcher_conf).is_ok() { // change the websocket reload state to true; // the page will auto-reload. if watcher_conf From 2c0b0460c9da1f8b30e3c91cce070e669b23d908 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 25 Jan 2022 18:01:33 +0800 Subject: [PATCH 038/895] fix: error wrap --- src/config.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/config.rs b/src/config.rs index 088955910..1151445ef 100644 --- a/src/config.rs +++ b/src/config.rs @@ -21,15 +21,8 @@ impl DioxusConfig { let mut meta_str = String::new(); dioxus_conf_file.read_to_string(&mut meta_str)?; - match toml::from_str::(&meta_str) { - Ok(v) => Ok(v), - Err(e) => { - log::error!("{}", e); - Err(crate::error::Error::Unique( - "Dioxus.toml parse failed".into(), - )) - } - } + toml::from_str::(&meta_str) + .map_err(|_| crate::Error::Unique("Dioxus.toml parse failed".into())) } } From 20977a49f0e0329dcdc77ccd01f4d5bb83fcf989 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 26 Jan 2022 00:21:40 +0800 Subject: [PATCH 039/895] fix: high CPU usage --- src/assets/autoreload.js | 17 ++++------- src/server/mod.rs | 63 ++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js index ff4444085..b2baa1907 100644 --- a/src/assets/autoreload.js +++ b/src/assets/autoreload.js @@ -5,21 +5,16 @@ var poll_interval = 2000; - var reload_upon_connect = () => { - window.setTimeout(() => { - var ws = new WebSocket(url); - ws.onopen = () => window.location.reload(); - ws.onclose = reload_upon_connect; - }, poll_interval); - }; - var ws = new WebSocket(url); - ws.onmessage = (ev) => { + ws.addEventListener("message", (ev) => { if (ev.data == "reload") { window.location.reload(); } - }; + }); + + ws.addEventListener("open", () => { + ws.send("init"); + }); - ws.onclose = reload_upon_connect; })(); \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index c7c9074ed..24504498a 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -20,8 +20,8 @@ struct WsRelodState { } impl WsRelodState { - fn change(&mut self) { - self.update = !self.update; + fn change(&mut self, state: bool) { + self.update = state; } } @@ -34,40 +34,35 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { // file watcher: check file change let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); - watcher - .watch(config.crate_dir.clone(), notify::RecursiveMode::Recursive) - .unwrap(); + let allow_watch_path = config + .dioxus_config + .web + .watcher + .watch_path + .clone() + .unwrap_or_else(|| vec![PathBuf::from("src")]); + for sub_path in allow_watch_path { + watcher + .watch( + config.crate_dir.join(sub_path), + notify::RecursiveMode::Recursive, + ) + .unwrap(); + } let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false })); let watcher_conf = config.clone(); let watcher_ws_state = ws_reload_state.clone(); tokio::spawn(async move { - let allow_watch_path = watcher_conf - .dioxus_config - .web - .watcher - .watch_path - .clone() - .unwrap_or_else(|| vec![PathBuf::from("src")]); - let crate_dir = watcher_conf.crate_dir.clone(); loop { if let Ok(v) = rx.recv() { match v { - DebouncedEvent::Create(e) - | DebouncedEvent::Write(e) - | DebouncedEvent::Remove(e) - | DebouncedEvent::Rename(e, _) => { - let mut should_reload = false; - for path in &allow_watch_path { - let temp = crate_dir.clone().join(path); - if e.starts_with(temp) { - should_reload = true; - break; - } - } - - if should_reload && builder::build(&watcher_conf).is_ok() { + DebouncedEvent::Create(_) + | DebouncedEvent::Write(_) + | DebouncedEvent::Remove(_) + | DebouncedEvent::Rename(_, _) => { + if builder::build(&watcher_conf).is_ok() { // change the websocket reload state to true; // the page will auto-reload. if watcher_conf @@ -79,7 +74,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { { let _ = Serve::regen_dev_page(&watcher_conf); } - watcher_ws_state.lock().unwrap().change(); + watcher_ws_state.lock().unwrap().change(true); } } _ => {} @@ -118,13 +113,17 @@ async fn ws_handler( ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { loop { - tokio::time::sleep(tokio::time::Duration::from_millis(1200)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; if state.lock().unwrap().update { - socket + // ignore the error + if socket .send(Message::Text(String::from("reload"))) .await - .unwrap(); - state.lock().unwrap().change(); + .is_err() + { + return; + } + state.lock().unwrap().change(false); } } }) From 78980b2dbf62278bf939ece72c67f9ab35a39807 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 26 Jan 2022 10:18:31 +0800 Subject: [PATCH 040/895] fix: use channel --- src/assets/autoreload.js | 4 ++++ src/server/mod.rs | 52 +++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js index b2baa1907..89054664e 100644 --- a/src/assets/autoreload.js +++ b/src/assets/autoreload.js @@ -17,4 +17,8 @@ ws.send("init"); }); + ws.addEventListener("close", () => { + alert("Dev-Server Socket Closed."); + }); + })(); \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index 24504498a..366ea41ab 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -9,31 +9,26 @@ use notify::{watcher, DebouncedEvent, Watcher}; use std::time::Duration; use std::{ path::PathBuf, - sync::{mpsc::channel, Arc, Mutex}, + sync::{mpsc::channel, Arc}, }; use tower_http::services::ServeDir; use crate::{builder, serve::Serve, CrateConfig}; +use tokio::sync::broadcast; struct WsRelodState { - update: bool, -} - -impl WsRelodState { - fn change(&mut self, state: bool) { - self.update = state; - } + update: broadcast::Sender, } pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { log::info!("🚀 Starting development server..."); - let (tx, rx) = channel(); + let (watcher_tx, watcher_rx) = channel(); let dist_path = config.out_dir.clone(); // file watcher: check file change - let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); + let mut watcher = watcher(watcher_tx, Duration::from_secs(1)).unwrap(); let allow_watch_path = config .dioxus_config .web @@ -50,13 +45,14 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { .unwrap(); } - let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false })); + let (reload_tx, _) = broadcast::channel(100); + let ws_reload_state = Arc::new(WsRelodState { update: reload_tx }); let watcher_conf = config.clone(); - let watcher_ws_state = ws_reload_state.clone(); + let watcher_ws_state = ws_reload_state.update.clone(); tokio::spawn(async move { loop { - if let Ok(v) = rx.recv() { + if let Ok(v) = watcher_rx.recv() { match v { DebouncedEvent::Create(_) | DebouncedEvent::Write(_) @@ -74,7 +70,8 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { { let _ = Serve::regen_dev_page(&watcher_conf); } - watcher_ws_state.lock().unwrap().change(true); + println!("send reload!"); + watcher_ws_state.send("reload".into()).unwrap(); } } _ => {} @@ -109,21 +106,26 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { async fn ws_handler( ws: WebSocketUpgrade, _: Option>, - Extension(state): Extension>>, + Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { + let mut rx = state.update.subscribe(); loop { - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - if state.lock().unwrap().update { - // ignore the error - if socket - .send(Message::Text(String::from("reload"))) - .await - .is_err() - { - return; + println!("wait"); + if let Ok(v) = rx.recv().await { + println!("trigger recv: {}", v); + if v == "reload" { + // ignore the error + if socket + .send(Message::Text(String::from("reload"))) + .await + .is_err() + { + return; + } } - state.lock().unwrap().change(false); + } else { + println!("SS"); } } }) From 7aeddba4270c404a1898382acd0b89b4b33096db Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 01:03:17 +0800 Subject: [PATCH 041/895] fix: auto-connect `ws` server --- src/assets/autoreload.js | 40 +++++++------- src/server/mod.rs | 111 ++++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 74 deletions(-) diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js index 89054664e..a6bbac5da 100644 --- a/src/assets/autoreload.js +++ b/src/assets/autoreload.js @@ -1,24 +1,22 @@ (function () { - var protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; - - var url = protocol + "//" + window.location.host + "/_dioxus/ws"; - - var poll_interval = 2000; + var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + var url = protocol + '//' + window.location.host + '/_dioxus/ws'; + var poll_interval = 8080; + var reload_upon_connect = () => { + window.setTimeout( + () => { + var ws = new WebSocket(url); + ws.onopen = () => window.location.reload(); + ws.onclose = reload_upon_connect; + }, + poll_interval); + }; var ws = new WebSocket(url); - - ws.addEventListener("message", (ev) => { - if (ev.data == "reload") { - window.location.reload(); - } - }); - - ws.addEventListener("open", () => { - ws.send("init"); - }); - - ws.addEventListener("close", () => { - alert("Dev-Server Socket Closed."); - }); - -})(); \ No newline at end of file + ws.onmessage = (ev) => { + if (ev.data == "reload") { + window.location.reload(); + } + }; + ws.onclose = reload_upon_connect; +})() \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index 366ea41ab..7dd4151eb 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -36,6 +36,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { .watch_path .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); + for sub_path in allow_watch_path { watcher .watch( @@ -46,60 +47,63 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { } let (reload_tx, _) = broadcast::channel(100); - let ws_reload_state = Arc::new(WsRelodState { update: reload_tx }); + + let ws_reload_state = Arc::new(WsRelodState { + update: reload_tx.clone(), + }); let watcher_conf = config.clone(); - let watcher_ws_state = ws_reload_state.update.clone(); + tokio::spawn(async move { - loop { - if let Ok(v) = watcher_rx.recv() { - match v { - DebouncedEvent::Create(_) - | DebouncedEvent::Write(_) - | DebouncedEvent::Remove(_) - | DebouncedEvent::Rename(_, _) => { - if builder::build(&watcher_conf).is_ok() { - // change the websocket reload state to true; - // the page will auto-reload. - if watcher_conf - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&watcher_conf); - } - println!("send reload!"); - watcher_ws_state.send("reload".into()).unwrap(); + while let Ok(v) = watcher_rx.recv() { + match v { + DebouncedEvent::Create(_) + | DebouncedEvent::Write(_) + | DebouncedEvent::Remove(_) + | DebouncedEvent::Rename(_, _) => { + if builder::build(&watcher_conf).is_ok() { + // change the websocket reload state to true; + // the page will auto-reload. + if watcher_conf + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&watcher_conf); } + reload_tx.send("reload".into()).unwrap(); } - _ => {} } + _ => {} } } }); - let app = Router::new() - .route("/_dioxus/ws", get(ws_handler)) - .fallback( - get_service(ServeDir::new(config.crate_dir.join(&dist_path))).handle_error( - |error: std::io::Error| async move { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Unhandled internal error: {}", error), - ) - }, - ), - ) - .layer(AddExtensionLayer::new(ws_reload_state.clone())); - // start serve dev-server at 0.0.0.0:8080 let port = "8080"; log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); + axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) - .serve(app.into_make_service()) + .serve( + Router::new() + .route("/_dioxus/ws", get(ws_handler)) + .fallback( + get_service(ServeDir::new(config.crate_dir.join(&dist_path))).handle_error( + |error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }, + ), + ) + .layer(AddExtensionLayer::new(ws_reload_state)) + .into_make_service(), + ) .await?; + Ok(()) } @@ -109,23 +113,24 @@ async fn ws_handler( Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { + + log::info!("New websocket conenct."); + let mut rx = state.update.subscribe(); + loop { - println!("wait"); - if let Ok(v) = rx.recv().await { - println!("trigger recv: {}", v); - if v == "reload" { - // ignore the error - if socket - .send(Message::Text(String::from("reload"))) - .await - .is_err() - { - return; - } + let v = rx.recv().await.unwrap(); + println!("trigger recv: {}", v); + if v == "reload" { + // ignore the error + if socket + .send(Message::Text(String::from("reload"))) + .await + .is_err() + { + println!("send failed"); + return; } - } else { - println!("SS"); } } }) From b6172998609812a02cc9e68786e0cd283bc0e685 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 11:13:41 +0800 Subject: [PATCH 042/895] fix: auto-reload --- Cargo.toml | 3 +- src/assets/autoreload.js | 1 + src/server/mod.rs | 131 +++++++++++++++++++++------------------ 3 files changed, 73 insertions(+), 62 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68dd3ee56..5f6443245 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ toml = "0.5.8" fs_extra = "1.2.0" cargo_toml = "0.10.0" futures = "0.3.12" -notify = "4.0.17" +# notify = "4.0.17" +notify = { version = "5.0.0-pre.13", features = ["serde"] } html_parser = "0.6.2" binary-install = "0.0.2" convert_case = "0.5.0" diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js index a6bbac5da..da62e5eae 100644 --- a/src/assets/autoreload.js +++ b/src/assets/autoreload.js @@ -15,6 +15,7 @@ var ws = new WebSocket(url); ws.onmessage = (ev) => { if (ev.data == "reload") { + // alert("reload!!!"); window.location.reload(); } }; diff --git a/src/server/mod.rs b/src/server/mod.rs index 7dd4151eb..45d7191d0 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -5,12 +5,9 @@ use axum::{ routing::{get, get_service}, AddExtensionLayer, Router, }; -use notify::{watcher, DebouncedEvent, Watcher}; -use std::time::Duration; -use std::{ - path::PathBuf, - sync::{mpsc::channel, Arc}, -}; +use notify::{RecommendedWatcher, Watcher}; + +use std::{path::PathBuf, sync::Arc}; use tower_http::services::ServeDir; use crate::{builder, serve::Serve, CrateConfig}; @@ -23,12 +20,33 @@ struct WsRelodState { pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { log::info!("🚀 Starting development server..."); - let (watcher_tx, watcher_rx) = channel(); - let dist_path = config.out_dir.clone(); + let (reload_tx, _) = broadcast::channel(100); + + let ws_reload_state = Arc::new(WsRelodState { + update: reload_tx.clone(), + }); + // file watcher: check file change - let mut watcher = watcher(watcher_tx, Duration::from_secs(1)).unwrap(); + let watcher_conf = config.clone(); + let mut watcher = RecommendedWatcher::new(move |_| { + if builder::build(&watcher_conf).is_ok() { + // change the websocket reload state to true; + // the page will auto-reload. + if watcher_conf + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&watcher_conf); + } + reload_tx.send("reload".into()).unwrap(); + } + }) + .unwrap(); let allow_watch_path = config .dioxus_config .web @@ -40,46 +58,38 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { for sub_path in allow_watch_path { watcher .watch( - config.crate_dir.join(sub_path), + &config.crate_dir.join(sub_path), notify::RecursiveMode::Recursive, ) .unwrap(); } - let (reload_tx, _) = broadcast::channel(100); - - let ws_reload_state = Arc::new(WsRelodState { - update: reload_tx.clone(), - }); - - let watcher_conf = config.clone(); - - tokio::spawn(async move { - while let Ok(v) = watcher_rx.recv() { - match v { - DebouncedEvent::Create(_) - | DebouncedEvent::Write(_) - | DebouncedEvent::Remove(_) - | DebouncedEvent::Rename(_, _) => { - if builder::build(&watcher_conf).is_ok() { - // change the websocket reload state to true; - // the page will auto-reload. - if watcher_conf - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&watcher_conf); - } - reload_tx.send("reload".into()).unwrap(); - } - } - _ => {} - } - } - }); + // tokio::spawn(async move { + // while let Ok(v) = watcher_rx.recv() { + // match v { + // DebouncedEvent::Create(_) + // | DebouncedEvent::Write(_) + // | DebouncedEvent::Remove(_) + // | DebouncedEvent::Rename(_, _) => { + // if builder::build(&watcher_conf).is_ok() { + // // change the websocket reload state to true; + // // the page will auto-reload. + // if watcher_conf + // .dioxus_config + // .web + // .watcher + // .reload_html + // .unwrap_or(false) + // { + // let _ = Serve::regen_dev_page(&watcher_conf); + // } + // reload_tx.send("reload".into()).unwrap(); + // } + // } + // _ => {} + // } + // } + // }); // start serve dev-server at 0.0.0.0:8080 let port = "8080"; @@ -113,25 +123,24 @@ async fn ws_handler( Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { - - log::info!("New websocket conenct."); - let mut rx = state.update.subscribe(); - - loop { - let v = rx.recv().await.unwrap(); - println!("trigger recv: {}", v); - if v == "reload" { - // ignore the error - if socket - .send(Message::Text(String::from("reload"))) - .await - .is_err() - { - println!("send failed"); - return; + let reload_watcher = tokio::spawn(async move { + loop { + let v = rx.recv().await.unwrap(); + println!("trigger recv: {}", v); + if v == "reload" { + // ignore the error + if socket + .send(Message::Text(String::from("reload"))) + .await + .is_err() + { + break; + } } } - } + }); + + reload_watcher.await.unwrap(); }) } From b8b0303904b3f01da5942355b5c61a5ea33c325c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 12:09:54 +0800 Subject: [PATCH 043/895] fix: dev server `auto-reload` --- Cargo.toml | 2 +- src/server/mod.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f6443245..5bbfd7ac2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ toml = "0.5.8" fs_extra = "1.2.0" cargo_toml = "0.10.0" futures = "0.3.12" -# notify = "4.0.17" notify = { version = "5.0.0-pre.13", features = ["serde"] } html_parser = "0.6.2" binary-install = "0.0.2" @@ -30,6 +29,7 @@ cargo_metadata = "0.14.1" tokio = { version = "1.15.0", features = ["full"] } atty = "0.2.14" regex = "1.5.4" +chrono = "0.4.19" axum = { version = "0.4.4", features = ["ws", "headers"] } tower-http = { version = "0.2.0", features = ["fs", "trace"] } diff --git a/src/server/mod.rs b/src/server/mod.rs index 45d7191d0..b1684d980 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -28,10 +28,14 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { update: reload_tx.clone(), }); + let mut last_update_time = chrono::Local::now().timestamp(); + // file watcher: check file change let watcher_conf = config.clone(); - let mut watcher = RecommendedWatcher::new(move |_| { - if builder::build(&watcher_conf).is_ok() { + let mut watcher = RecommendedWatcher::new(move | _ : notify::Result| { + if chrono::Local::now().timestamp() > last_update_time + && builder::build(&watcher_conf).is_ok() + { // change the websocket reload state to true; // the page will auto-reload. if watcher_conf @@ -43,7 +47,9 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { { let _ = Serve::regen_dev_page(&watcher_conf); } + println!("watcher send reload"); reload_tx.send("reload".into()).unwrap(); + last_update_time = chrono::Local::now().timestamp(); } }) .unwrap(); @@ -127,7 +133,6 @@ async fn ws_handler( let reload_watcher = tokio::spawn(async move { loop { let v = rx.recv().await.unwrap(); - println!("trigger recv: {}", v); if v == "reload" { // ignore the error if socket From 23e09f0d9f0b3740cb9b9809e3efdd0f2652c21c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 14:11:18 +0800 Subject: [PATCH 044/895] fix: delete comment --- src/server/mod.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index b1684d980..880f25ceb 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -32,7 +32,7 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { // file watcher: check file change let watcher_conf = config.clone(); - let mut watcher = RecommendedWatcher::new(move | _ : notify::Result| { + let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { if chrono::Local::now().timestamp() > last_update_time && builder::build(&watcher_conf).is_ok() { @@ -70,33 +70,6 @@ pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { .unwrap(); } - // tokio::spawn(async move { - // while let Ok(v) = watcher_rx.recv() { - // match v { - // DebouncedEvent::Create(_) - // | DebouncedEvent::Write(_) - // | DebouncedEvent::Remove(_) - // | DebouncedEvent::Rename(_, _) => { - // if builder::build(&watcher_conf).is_ok() { - // // change the websocket reload state to true; - // // the page will auto-reload. - // if watcher_conf - // .dioxus_config - // .web - // .watcher - // .reload_html - // .unwrap_or(false) - // { - // let _ = Serve::regen_dev_page(&watcher_conf); - // } - // reload_tx.send("reload".into()).unwrap(); - // } - // } - // _ => {} - // } - // } - // }); - // start serve dev-server at 0.0.0.0:8080 let port = "8080"; log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); From b23e69cfbbf0af2d96ab897bf45e3944f863be59 Mon Sep 17 00:00:00 2001 From: c5soft Date: Thu, 27 Jan 2022 15:54:49 +0800 Subject: [PATCH 045/895] Refactor extension, make it easy to maintain and unique to register --- extension/LICENSE.txt | 21 +++++++++++ extension/package.json | 15 ++++---- extension/src/extension.ts | 75 +++++++++++++------------------------- 3 files changed, 54 insertions(+), 57 deletions(-) create mode 100644 extension/LICENSE.txt diff --git a/extension/LICENSE.txt b/extension/LICENSE.txt new file mode 100644 index 000000000..6fd3d45f6 --- /dev/null +++ b/extension/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 DioxusLabs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extension/package.json b/extension/package.json index 3b72cfa8c..0a3d50b67 100644 --- a/extension/package.json +++ b/extension/package.json @@ -17,19 +17,19 @@ "Other" ], "activationEvents": [ - "onCommand:extension.htmlToRsx", - "onCommand:extension.htmlToComponent" + "onCommand:extension.htmlToDioxusRsx", + "onCommand:extension.htmlToDioxusComponent" ], "main": "./out/extension", "contributes": { "commands": [ { - "command": "extension.htmlToRsx", - "title": "Convert HTML to RSX" + "command": "extension.htmlToDioxusRsx", + "title": "Dioxus: Convert HTML to RSX" }, { - "command": "extension.htmlToComponent", - "title": "Convert HTML to Dioxus Component" + "command": "extension.htmlToDioxusComponent", + "title": "Dioxus: Convert HTML to Component" } ] }, @@ -37,7 +37,8 @@ "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "lint": "eslint . --ext .ts,.tsx", - "watch": "tsc -watch -p ./" + "watch": "tsc -watch -p ./", + "package": "vsce package" }, "devDependencies": { "@types/node": "^12.12.0", diff --git a/extension/src/extension.ts b/extension/src/extension.ts index c9ab06662..5a41c7f5f 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -1,57 +1,32 @@ -'use strict'; - import * as vscode from 'vscode'; import { spawn } from "child_process"; export function activate(context: vscode.ExtensionContext) { - const htmlToPureRsx = vscode.commands.registerCommand('extension.htmlToRsx', function () { - // Get the active text editor - const editor = vscode.window.activeTextEditor; - - if (editor) { - const document = editor.document; - const selection = editor.selection; - const word = document.getText(selection); - - const child_proc = spawn("dioxus", ["translate", "--source", word]); - - let result = ''; - child_proc.stdout?.on('data', data => result += data); - - child_proc.on('close', () => { - editor.edit(editBuilder => { - if (result != '') { - editBuilder.replace(selection, result) - } - }) - }); + function registerCommand(cmd: string) { + function convert(cmd: string) { + const editor = vscode.window.activeTextEditor;// Get the active text editor + if (editor) { + const html = editor.document.getText(editor.selection); + if (html.length > 0) { + let params = ["translate"]; + if (cmd.includes("Component")) params.push("--component"); + params.push("--source"); + params.push(html); + const child_proc = spawn("dioxus", params); + let result = ''; + child_proc.stdout?.on('data', data => result += data); + child_proc.on('close', () => { + if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); + }); + } else { + vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!"); + } + } } - }); + const handle = vscode.commands.registerCommand(cmd, () => convert(cmd)); + context.subscriptions.push(handle); + } - const htmlToComponent = vscode.commands.registerCommand('extension.htmlToComponent', function () { - // Get the active text editor - const editor = vscode.window.activeTextEditor; - - if (editor) { - const document = editor.document; - const selection = editor.selection; - const word = document.getText(selection); - - const child_proc = spawn("dioxus", ["translate", "--component", "--source", word]); - - let result = ''; - child_proc.stdout?.on('data', data => result += data); - - child_proc.on('close', () => { - editor.edit(editBuilder => { - if (result != '') { - editBuilder.replace(selection, result) - } - }) - }); - } - }); - - context.subscriptions.push(htmlToPureRsx); - context.subscriptions.push(htmlToComponent); + registerCommand('extension.htmlToDioxusRsx'); + registerCommand('extension.htmlToDioxusComponent'); } From 5d9a58b0faae85375b523ea3fa70ce29d58b141c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 23:06:09 +0800 Subject: [PATCH 046/895] fix: desktop build --- src/builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 583c9bc8f..257072a6a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -141,6 +141,10 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { let output = cmd.output()?; + if !output.status.success() { + return Err(Error::BuildFailed("Program build failed.".into())); + } + if output.status.success() { if config.out_dir.is_dir() { remove_dir_all(&config.out_dir)?; From efe956a1bfd097a2190a7db95286dafe1a2c09d9 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 27 Jan 2022 23:56:44 +0800 Subject: [PATCH 047/895] fix: display log --- src/cli/serve/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index fd8f3c4f5..8f26e0f30 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,5 +1,5 @@ use crate::{cfg::ConfigOptsServe, gen_page, server, CrateConfig}; -use std::{io::Write, path::PathBuf, process::Command}; +use std::{io::Write, path::PathBuf, process::{Command, Stdio}}; use structopt::StructOpt; /// Run the WASM project on dev-server @@ -44,6 +44,7 @@ impl Serve { .unwrap() .to_string(), ) + .stdout(Stdio::inherit()) .output()?; } } From a4ae4598fbf4aa41562efe2c0afbf37049da7ba8 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sat, 5 Feb 2022 09:11:44 +0800 Subject: [PATCH 048/895] docs: update reamde --- README.md | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 75e05b3cf..7bc1fa131 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,46 @@

📦✨ dioxus-cli

-

- Tooling to supercharge dioxus projects -

+

Tooling to supercharge dioxus projects

-![Dioxus Logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png) - - -# About - dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development simple. - ## Installation ``` $ cargo install dioxus-cli ``` -Now, `dioxus` is in your path. \ No newline at end of file +Now, `dioxus` is in your path, you can use `dioxus --help` to get the help document. + +``` +dioxus 0.1.2 +Build, bundle, & ship your Dioxus app + +USAGE: + dioxus.exe [FLAGS] + +FLAGS: + -h, --help Prints help information + -v Enable verbose logging + -V, --version Prints version information + +SUBCOMMANDS: + build Build the Rust WASM app and all of its assets + clean Clean output artifacts + config Dioxus config file controls + create Init a new project for Dioxus + help Prints this message or the help of the given subcommand(s) + serve Build, watch & serve the Rust WASM app and all of its assets + translate Translate some source file into Dioxus code +``` + +## Get Started + +You can use the `dioxus crate project_name` to init a dioxus project, its will be clone from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template). + +or you can assign the template path: + +``` +dioxus create hello --template gh:dioxuslabs/dioxus-template +``` \ No newline at end of file From 025efc912075348bb90fbaed1cde3e5c61c8ccf9 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 6 Feb 2022 16:28:17 -0500 Subject: [PATCH 049/895] fix: translation service --- src/cli/translate/extract_svgs.rs | 1 - src/cli/translate/mod.rs | 240 ++++++++++++++++++++++++------ src/cli/translate/to_component.rs | 183 ----------------------- src/cli/translate/translate.rs | 1 - 4 files changed, 192 insertions(+), 233 deletions(-) delete mode 100644 src/cli/translate/extract_svgs.rs delete mode 100644 src/cli/translate/to_component.rs delete mode 100644 src/cli/translate/translate.rs diff --git a/src/cli/translate/extract_svgs.rs b/src/cli/translate/extract_svgs.rs deleted file mode 100644 index 8b1378917..000000000 --- a/src/cli/translate/extract_svgs.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index 81b5092ed..a717d632a 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -1,15 +1,14 @@ +use anyhow::Result; use html_parser::Dom; +use html_parser::Element; use html_parser::Node; -use std::fmt::Write; +#[allow(unused_imports)] +use std::fmt::{Display, Formatter}; use std::io::Read; use std::path::PathBuf; use std::process::exit; use structopt::StructOpt; -pub mod extract_svgs; -pub mod to_component; -pub mod translate; - /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, StructOpt)] #[structopt(name = "translate")] @@ -21,11 +20,7 @@ pub struct Translate { /// Input file #[structopt(short, long)] - pub source: Option, - - /// Input file - #[structopt(short, long, parse(from_os_str))] - pub input: Option, + pub file: Option, /// Output file, stdout if not present #[structopt(parse(from_os_str))] @@ -35,23 +30,17 @@ pub struct Translate { impl Translate { pub fn translate(self) -> anyhow::Result<()> { let Translate { - component: as_component, - input, + component, output, - source, + file, } = self; - let contents; - let temp = input.map(|f| { - std::fs::read_to_string(&f).unwrap_or_else(|e| { + let contents = match file { + Some(input) => std::fs::read_to_string(&input).unwrap_or_else(|e| { log::error!("Cloud not read input file: {}.", e); exit(0); - }) - }); - if let Some(..) = temp { - if let Some(s) = source { - contents = s; - } else { + }), + None => { if atty::is(atty::Stream::Stdin) { log::error!("No input file, source, or stdin to translate from."); exit(0); @@ -60,28 +49,21 @@ impl Translate { let mut buffer = String::new(); std::io::stdin().read_to_string(&mut buffer).unwrap(); - contents = buffer.trim().to_string(); + buffer.trim().to_string() } - } else { - contents = temp.unwrap(); - } + }; - // parse the input as html and prepare the output - let dom = Dom::parse(&contents)?; - let mut out_buf = String::new(); - - if as_component { - writeln!(out_buf, "use dioxus::prelude::*;")?; - writeln!(out_buf, "fn component(cx: Scope) -> Element {{")?; - writeln!(out_buf, " cx.render(rsx!(")?; - } - for child in &dom.children { - render_child(&mut out_buf, child, if as_component { 2 } else { 0 })?; - } - if as_component { - writeln!(out_buf, " ))")?; - writeln!(out_buf, "}}")?; - } + let out_buf = match component { + true => format!("{}", convert_html_to_component(&contents).unwrap()), + false => { + let mut buf = String::new(); + let dom = Dom::parse(&contents).unwrap(); + for child in &dom.children { + simple_render_child(&mut buf, child, 0)?; + } + buf + } + }; if let Some(output) = output { std::fs::write(&output, out_buf)?; @@ -93,7 +75,8 @@ impl Translate { } } -fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result { +/// render without handling svgs or anything +fn simple_render_child(f: &mut impl std::fmt::Write, child: &Node, il: u32) -> std::fmt::Result { write_tabs(f, il)?; match child { Node::Text(t) => writeln!(f, "\"{}\"", t)?, @@ -131,9 +114,8 @@ fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result { None => writeln!(f, "{}: \"\",", new_name)?, } } else { - match name.as_str() { - "for" | "async" | "type" | "as" => write!(f, "r#")?, - _ => {} + if matches!(name.as_str(), "for" | "async" | "type" | "as") { + write!(f, "r#")? } match value { @@ -145,7 +127,7 @@ fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result { // now the children for child in &el.children { - render_child(f, child, il + 1)?; + simple_render_child(f, child, il + 1)?; } // close the tag @@ -156,9 +138,171 @@ fn render_child(f: &mut impl Write, child: &Node, il: u32) -> std::fmt::Result { Ok(()) } -fn write_tabs(f: &mut impl Write, num: u32) -> std::fmt::Result { +pub fn convert_html_to_component(html: &str) -> Result { + Ok(ComponentRenderer { + dom: Dom::parse(html)?, + icon_index: 0, + }) +} + +#[allow(dead_code)] +pub struct ComponentRenderer { + dom: Dom, + icon_index: usize, +} + +impl Display for ComponentRenderer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + r##" +fn component(cx: Scope) -> Element {{ + cx.render(rsx!("## + )?; + let mut svg_nodes = vec![]; + + let mut svg_idx = 0; + for child in &self.dom.children { + render_child(f, child, 2, &mut svg_nodes, true, &mut svg_idx)?; + } + write!( + f, + r##" )) +}}"## + )?; + + if svg_idx == 0 { + return Ok(()); + } + + writeln!(f, "\n\nmod icons {{")?; + + let mut id = 0; + while let Some(svg) = svg_nodes.pop() { + writeln!( + f, + r##" pub(super) fn icon_{}(cx: Scope) -> Element {{ + cx.render(rsx!("##, + id + )?; + write_tabs(f, 3)?; + + render_element(f, svg, 3, &mut svg_nodes, false, &mut 0)?; + writeln!(f, "\t\t))\n\t}}\n")?; + id += 1; + } + + writeln!(f, "}}")?; + + Ok(()) + } +} + +fn render_child<'a>( + f: &mut Formatter<'_>, + child: &'a Node, + il: u32, + svg_buffer: &mut Vec<&'a Element>, + skip_svg: bool, + svg_idx: &mut usize, +) -> std::fmt::Result { + write_tabs(f, il)?; + match child { + Node::Text(t) => writeln!(f, "\"{}\"", t)?, + Node::Comment(e) => writeln!(f, "/* {} */", e)?, + Node::Element(el) => render_element(f, el, il, svg_buffer, skip_svg, svg_idx)?, + }; + Ok(()) +} + +fn render_element<'a>( + f: &mut Formatter<'_>, + el: &'a Element, + il: u32, + svg_buffer: &mut Vec<&'a Element>, + skip_svg: bool, + svg_idx: &mut usize, +) -> std::fmt::Result { + if el.name == "svg" && skip_svg { + svg_buffer.push(el); + // todo: attach the right icon ID + writeln!(f, "icons::icon_{} {{}}", svg_idx)?; + *svg_idx += 1; + return Ok(()); + } + + // open the tag + write!(f, "{} {{ ", &el.name)?; + + // todo: dioxus will eventually support classnames + // for now, just write them with a space between each + let class_iter = &mut el.classes.iter(); + if let Some(first_class) = class_iter.next() { + write!(f, "class: \"{}", first_class)?; + for next_class in class_iter { + write!(f, " {}", next_class)?; + } + write!(f, "\",")?; + } + writeln!(f)?; + + // write the attributes + if let Some(id) = &el.id { + write_tabs(f, il + 1)?; + writeln!(f, "id: \"{}\",", id)?; + } + + for (name, value) in &el.attributes { + write_tabs(f, il + 1)?; + + use convert_case::{Case, Casing}; + if name.chars().any(|ch| ch.is_ascii_uppercase() || ch == '-') { + let new_name = name.to_case(Case::Snake); + match value { + Some(val) => writeln!(f, "{}: \"{}\",", new_name, val)?, + None => writeln!(f, "{}: \"\",", new_name)?, + } + } else { + if matches!(name.as_str(), "for" | "async" | "type" | "as") { + write!(f, "r#")? + } + + match value { + Some(val) => writeln!(f, "{}: \"{}\",", name, val)?, + None => writeln!(f, "{}: \"\",", name)?, + } + } + } + + // now the children + for child in &el.children { + render_child(f, child, il + 1, svg_buffer, skip_svg, svg_idx)?; + } + + // close the tag + write_tabs(f, il)?; + writeln!(f, "}}")?; + Ok(()) +} + +fn write_tabs(f: &mut impl std::fmt::Write, num: u32) -> std::fmt::Result { for _ in 0..num { write!(f, " ")? } Ok(()) } + +#[test] +fn generates_svgs() { + use std::io::Write; + + let st = include_str!("../../../tests/svg.html"); + + let out = format!("{:}", convert_html_to_component(st).unwrap()); + dbg!(&out); + + std::fs::File::create("svg_rsx.rs") + .unwrap() + .write_all(out.as_bytes()) + .unwrap(); +} diff --git a/src/cli/translate/to_component.rs b/src/cli/translate/to_component.rs deleted file mode 100644 index c83777ccb..000000000 --- a/src/cli/translate/to_component.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! Intelligently converts html to rsx with appropraite transformations and extractions. -//! -//! - [*] Creates a component -//! - [ ] Extracts svgs -//! - [ ] Attempts to extract lists - -#[allow(unused_imports)] -use std::{ - fmt::{Display, Formatter}, - io::Write, -}; - -use anyhow::Result; - -use html_parser::{Dom, Element, Node}; - -pub fn convert_html_to_component(html: &str) -> Result { - Ok(ComponentRenderer { - dom: Dom::parse(html)?, - icon_index: 0, - }) -} - -#[allow(dead_code)] -pub struct ComponentRenderer { - dom: Dom, - icon_index: usize, -} - -impl Display for ComponentRenderer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!( - f, - r##" -fn component(cx: Scope) -> Element {{ - cx.render(rsx!("## - )?; - let mut svg_nodes = vec![]; - - let mut svg_idx = 0; - for child in &self.dom.children { - render_child(f, child, 2, &mut svg_nodes, true, &mut svg_idx)?; - } - write!( - f, - r##" )) -}}"## - )?; - - if svg_idx == 0 { - return Ok(()); - } - - writeln!(f, "\n\nmod icons {{")?; - - let mut id = 0; - while let Some(svg) = svg_nodes.pop() { - writeln!( - f, - r##" pub(super) fn icon_{}(cx: Scope) -> Element {{ - cx.render(rsx!("##, - id - )?; - write_tabs(f, 3)?; - - render_element(f, svg, 3, &mut svg_nodes, false, &mut 0)?; - writeln!(f, "\t\t))\n\t}}\n")?; - id += 1; - } - - writeln!(f, "}}")?; - - Ok(()) - } -} - -fn render_child<'a>( - f: &mut Formatter<'_>, - child: &'a Node, - il: u32, - svg_buffer: &mut Vec<&'a Element>, - skip_svg: bool, - svg_idx: &mut usize, -) -> std::fmt::Result { - write_tabs(f, il)?; - match child { - Node::Text(t) => writeln!(f, "\"{}\"", t)?, - Node::Comment(e) => writeln!(f, "/* {} */", e)?, - Node::Element(el) => render_element(f, el, il, svg_buffer, skip_svg, svg_idx)?, - }; - Ok(()) -} - -fn render_element<'a>( - f: &mut Formatter<'_>, - el: &'a Element, - il: u32, - svg_buffer: &mut Vec<&'a Element>, - skip_svg: bool, - svg_idx: &mut usize, -) -> std::fmt::Result { - if el.name == "svg" && skip_svg { - svg_buffer.push(el); - // todo: attach the right icon ID - writeln!(f, "icons::icon_{} {{}}", svg_idx)?; - *svg_idx += 1; - return Ok(()); - } - - // open the tag - write!(f, "{} {{ ", &el.name)?; - - // todo: dioxus will eventually support classnames - // for now, just write them with a space between each - let class_iter = &mut el.classes.iter(); - if let Some(first_class) = class_iter.next() { - write!(f, "class: \"{}", first_class)?; - for next_class in class_iter { - write!(f, " {}", next_class)?; - } - write!(f, "\",")?; - } - writeln!(f)?; - - // write the attributes - if let Some(id) = &el.id { - write_tabs(f, il + 1)?; - writeln!(f, "id: \"{}\",", id)?; - } - - for (name, value) in &el.attributes { - write_tabs(f, il + 1)?; - - use convert_case::{Case, Casing}; - if name.chars().any(|ch| ch.is_ascii_uppercase() || ch == '-') { - let new_name = name.to_case(Case::Snake); - match value { - Some(val) => writeln!(f, "{}: \"{}\",", new_name, val)?, - None => writeln!(f, "{}: \"\",", new_name)?, - } - } else { - match name.as_str() { - "for" | "async" | "type" | "as" => write!(f, "r#")?, - _ => {} - } - - match value { - Some(val) => writeln!(f, "{}: \"{}\",", name, val)?, - None => writeln!(f, "{}: \"\",", name)?, - } - } - } - - // now the children - for child in &el.children { - render_child(f, child, il + 1, svg_buffer, skip_svg, svg_idx)?; - } - - // close the tag - write_tabs(f, il)?; - writeln!(f, "}}")?; - Ok(()) -} - -fn write_tabs(f: &mut Formatter, num: u32) -> std::fmt::Result { - for _ in 0..num { - write!(f, " ")? - } - Ok(()) -} - -#[test] -fn generates_svgs() { - let st = include_str!("../../../tests/svg.html"); - - let out = format!("{:}", convert_html_to_component(st).unwrap()); - dbg!(&out); - - std::fs::File::create("svg_rsx.rs") - .unwrap() - .write_all(out.as_bytes()) - .unwrap(); -} diff --git a/src/cli/translate/translate.rs b/src/cli/translate/translate.rs deleted file mode 100644 index 8b1378917..000000000 --- a/src/cli/translate/translate.rs +++ /dev/null @@ -1 +0,0 @@ - From eb7388794a09eae788ad70aaabfb483e37cc19b3 Mon Sep 17 00:00:00 2001 From: Aster Date: Mon, 7 Feb 2022 05:28:18 +0800 Subject: [PATCH 050/895] Replace struct-opt with clap --- .gitignore | 1 + Cargo.toml | 26 +++++++++++++------------- README.md | 7 ++++++- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 96ef6c0b9..2e049011e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +.idea/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5bbfd7ac2..0f2ad96c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dioxus-cli" -version = "0.1.2" +version = "0.1.3" authors = ["Jonathan Kelley"] edition = "2018" description = "CLI tool for developing, testing, and publishing Dioxus apps" @@ -9,31 +9,31 @@ license = "MIT/Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -thiserror = "1.0.23" -log = "0.4.13" +thiserror = "1.0.30" +log = "0.4.14" fern = { version = "0.6.0", features = ["colored"] } wasm-bindgen-cli-support = "0.2.79" -anyhow = "1.0.38" -serde = { version = "1.0.133", features = ["derive"] } -serde_json = "1" +anyhow = "1.0.53" +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" toml = "0.5.8" fs_extra = "1.2.0" -cargo_toml = "0.10.0" -futures = "0.3.12" +cargo_toml = "0.11.4" +futures = "0.3.21" notify = { version = "5.0.0-pre.13", features = ["serde"] } html_parser = "0.6.2" binary-install = "0.0.2" convert_case = "0.5.0" -structopt = "0.3.25" cargo_metadata = "0.14.1" -tokio = { version = "1.15.0", features = ["full"] } +tokio = { version = "1.16.1", features = ["full"] } atty = "0.2.14" regex = "1.5.4" chrono = "0.4.19" +clap = "3.0.14" -axum = { version = "0.4.4", features = ["ws", "headers"] } -tower-http = { version = "0.2.0", features = ["fs", "trace"] } -headers = "0.3" +axum = { version = "0.4.5", features = ["ws", "headers"] } +tower-http = { version = "0.2.2", features = ["fs", "trace"] } +headers = "0.3.7" # hyper = { version = "0.14.11", features = ["full"] } [[bin]] diff --git a/README.md b/README.md index 75e05b3cf..ab4cf1225 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,13 @@ dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus proj ## Installation -``` +```shell +# for stable $ cargo install dioxus-cli +# for latest +$ cargo install --git https://github.com/DioxusLabs/cli +# for developing +$ cargo install --path . --debug ``` Now, `dioxus` is in your path. \ No newline at end of file From b6c6dd6532335c5acd2c2eea54300f6f6b341a64 Mon Sep 17 00:00:00 2001 From: Aster Date: Tue, 8 Feb 2022 00:51:21 +0800 Subject: [PATCH 051/895] Clean struct-opt derive --- Cargo.toml | 7 ++++--- src/cli/build/mod.rs | 8 +++----- src/cli/cfg.rs | 9 +++------ src/cli/clean/mod.rs | 10 ++-------- src/cli/config/mod.rs | 7 ++----- src/cli/create/mod.rs | 13 +------------ src/cli/mod.rs | 33 ++++++++++++++++++++++++++------- src/cli/serve/mod.rs | 6 ++---- src/cli/translate/mod.rs | 13 ++----------- tests/main.rs | 4 ++++ 10 files changed, 49 insertions(+), 61 deletions(-) create mode 100644 tests/main.rs diff --git a/Cargo.toml b/Cargo.toml index 0f2ad96c4..89943ec62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,13 @@ license = "MIT/Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# cli core +clap = {version = "3.0.14", features = ["derive"]} thiserror = "1.0.30" +wasm-bindgen-cli-support = "0.2.79" +# features log = "0.4.14" fern = { version = "0.6.0", features = ["colored"] } -wasm-bindgen-cli-support = "0.2.79" -anyhow = "1.0.53" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" toml = "0.5.8" @@ -29,7 +31,6 @@ tokio = { version = "1.16.1", features = ["full"] } atty = "0.2.14" regex = "1.5.4" chrono = "0.4.19" -clap = "3.0.14" axum = { version = "0.4.5", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 684cec58c..b4d7f5fe4 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,10 +1,8 @@ -use std::{io::Write, path::PathBuf}; +use super::*; -use crate::{cfg::ConfigOptsBuild, gen_page}; -use structopt::StructOpt; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, StructOpt)] +#[derive(Clone, Debug, Parser)] #[structopt(name = "build")] pub struct Build { #[structopt(flatten)] @@ -15,7 +13,7 @@ impl Build { pub fn build(self) -> anyhow::Result<()> { let mut crate_config = crate::CrateConfig::new()?; - // change the relase state. + // change the release state. crate_config.with_release(self.build.release); if self.build.example.is_some() { diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index ece00e07e..fdd627e85 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -1,10 +1,7 @@ -use std::path::PathBuf; -use structopt::StructOpt; - -use serde::Deserialize; +use super::*; /// Config options for the build system. -#[derive(Clone, Debug, Default, Deserialize, StructOpt)] +#[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsBuild { /// The index HTML file to drive the bundling process [default: index.html] #[structopt(parse(from_os_str))] @@ -24,7 +21,7 @@ pub struct ConfigOptsBuild { pub platform: String, } -#[derive(Clone, Debug, Default, Deserialize, StructOpt)] +#[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsServe { /// The index HTML file to drive the bundling process [default: index.html] #[structopt(parse(from_os_str))] diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index 62593b1ee..334f93572 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -1,13 +1,7 @@ -use std::{ - fs::remove_dir_all, - path::PathBuf, - process::{Command, Stdio}, -}; - -use structopt::StructOpt; +use super::*; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, StructOpt)] +#[derive(Clone, Debug, Parser)] #[structopt(name = "clean")] pub struct Clean {} diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index d5291a7d6..e5d7bdbe4 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -1,10 +1,7 @@ -use std::{fs::File, io::Write}; - -use serde::Deserialize; -use structopt::StructOpt; +use super::*; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, Deserialize, StructOpt)] +#[derive(Clone, Debug, Deserialize, Parser)] #[structopt(name = "config")] pub enum Config { /// Init `Dioxus.toml` for project/folder. diff --git a/src/cli/create/mod.rs b/src/cli/create/mod.rs index fa553c55a..b92a193b7 100644 --- a/src/cli/create/mod.rs +++ b/src/cli/create/mod.rs @@ -1,15 +1,4 @@ -use std::{ - fs::File, - io::{Read, Write}, - path::PathBuf, - process::{Command, Stdio}, -}; - -use regex::Regex; -use serde::Deserialize; -use structopt::StructOpt; - -use crate::{error::Result, Error}; +use super::*; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Default, Deserialize, StructOpt)] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 4a72e00ac..e3bd18b3b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,5 +1,3 @@ -use structopt::StructOpt; - pub mod build; pub mod cfg; pub mod clean; @@ -8,17 +6,38 @@ pub mod create; pub mod serve; pub mod translate; +use std::{io::Write, path::PathBuf}; +use crate::{cfg::ConfigOptsBuild, gen_page}; +use clap::{Parser}; +use serde::Deserialize; +use std::{ + fs::remove_dir_all, + process::{Command, Stdio}, +}; +use std::{fs::File}; +use std::{ + io::{Read}, +}; +use regex::Regex; +use crate::{error::Result, Error}; +use crate::{cfg::ConfigOptsServe, server, CrateConfig}; +use html_parser::Dom; +use html_parser::Element; +use html_parser::Node; +use std::fmt::{Display, Formatter}; +use std::process::exit; + /// Build, bundle, & ship your Dioxus app. /// /// -#[derive(StructOpt)] -#[structopt(name = "dioxus")] +#[derive(Parser, Debug)] +#[clap(name = "dioxus")] pub struct Cli { - #[structopt(subcommand)] + #[clap(subcommand)] pub action: Commands, /// Enable verbose logging. - #[structopt(short)] + #[clap(short)] pub v: bool, // // // note: dioxus is still roughly compatible with trunk @@ -27,7 +46,7 @@ pub struct Cli { // pub config: Option, } -#[derive(StructOpt)] +#[derive(Parser)] pub enum Commands { /// Build the Rust WASM app and all of its assets. Build(build::Build), diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 8f26e0f30..d7184f5f9 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,9 +1,7 @@ -use crate::{cfg::ConfigOptsServe, gen_page, server, CrateConfig}; -use std::{io::Write, path::PathBuf, process::{Command, Stdio}}; -use structopt::StructOpt; +use super::*; /// Run the WASM project on dev-server -#[derive(Clone, Debug, StructOpt)] +#[derive(Clone, Debug, Parser)] #[structopt(name = "serve")] pub struct Serve { #[structopt(flatten)] diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index a717d632a..4e23533aa 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -1,16 +1,7 @@ -use anyhow::Result; -use html_parser::Dom; -use html_parser::Element; -use html_parser::Node; -#[allow(unused_imports)] -use std::fmt::{Display, Formatter}; -use std::io::Read; -use std::path::PathBuf; -use std::process::exit; -use structopt::StructOpt; +use super::*; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, StructOpt)] +#[derive(Clone, Debug, Parser)] #[structopt(name = "translate")] pub struct Translate { /// Activate debug mode diff --git a/tests/main.rs b/tests/main.rs new file mode 100644 index 000000000..f9bb6a890 --- /dev/null +++ b/tests/main.rs @@ -0,0 +1,4 @@ +#[test] +fn ready() { + println!("Compiled successfully!") +} \ No newline at end of file From ce628e1197095c778432fcb51df6d5f176a4f868 Mon Sep 17 00:00:00 2001 From: Aster Date: Wed, 9 Feb 2022 16:11:02 +0800 Subject: [PATCH 052/895] Fix compiler errors --- Cargo.toml | 2 ++ src/cli/build/mod.rs | 9 ++++----- src/cli/cfg.rs | 16 ++++++++-------- src/cli/clean/mod.rs | 4 ++-- src/cli/config/mod.rs | 9 +++++---- src/cli/create/mod.rs | 20 ++++++++------------ src/cli/mod.rs | 33 +++++++++++++++++---------------- src/cli/serve/mod.rs | 10 +++++----- src/cli/translate/mod.rs | 10 +++++----- src/error.rs | 37 +++++++++++++++++++++++++++++++++++++ src/main.rs | 4 ++-- src/server/mod.rs | 3 ++- tests/main.rs | 8 ++++---- 13 files changed, 101 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89943ec62..3ae7b4610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,8 @@ tokio = { version = "1.16.1", features = ["full"] } atty = "0.2.14" regex = "1.5.4" chrono = "0.4.19" +anyhow = "1.0.53" +hyper = "0.14.17" axum = { version = "0.4.5", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index b4d7f5fe4..1c665abd3 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -1,16 +1,15 @@ use super::*; - /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Parser)] -#[structopt(name = "build")] +#[clap(name = "build")] pub struct Build { - #[structopt(flatten)] + #[clap(flatten)] pub build: ConfigOptsBuild, } impl Build { - pub fn build(self) -> anyhow::Result<()> { + pub fn build(self) -> Result<()> { let mut crate_config = crate::CrateConfig::new()?; // change the release state. @@ -28,7 +27,7 @@ impl Build { crate::builder::build_desktop(&crate_config)?; } _ => { - return Err(anyhow::anyhow!("Unsoppurt platform target.")); + return custom_error!("Unsoppurt platform target."); } } diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index fdd627e85..f1e3d0845 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -4,40 +4,40 @@ use super::*; #[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsBuild { /// The index HTML file to drive the bundling process [default: index.html] - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] pub target: Option, /// Build in release mode [default: false] - #[structopt(long)] + #[clap(long)] #[serde(default)] pub release: bool, /// Build a example [default: ""] - #[structopt(long)] + #[clap(long)] pub example: Option, /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long, default_value = "web")] + #[clap(long, default_value = "web")] pub platform: String, } #[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsServe { /// The index HTML file to drive the bundling process [default: index.html] - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] pub target: Option, /// Build a example [default: ""] - #[structopt(long)] + #[clap(long)] pub example: Option, /// Build in release mode [default: false] - #[structopt(long)] + #[clap(long)] #[serde(default)] pub release: bool, /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long, default_value = "web")] + #[clap(long, default_value = "web")] pub platform: String, } diff --git a/src/cli/clean/mod.rs b/src/cli/clean/mod.rs index 334f93572..74a99fec2 100644 --- a/src/cli/clean/mod.rs +++ b/src/cli/clean/mod.rs @@ -2,11 +2,11 @@ use super::*; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Parser)] -#[structopt(name = "clean")] +#[clap(name = "clean")] pub struct Clean {} impl Clean { - pub fn clean(self) -> anyhow::Result<()> { + pub fn clean(self) -> Result<()> { let crate_config = crate::CrateConfig::new()?; let output = Command::new("cargo") diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index e5d7bdbe4..3cbf368e0 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -1,8 +1,9 @@ use super::*; + /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, Deserialize, Parser)] -#[structopt(name = "config")] +#[derive(Clone, Debug, Deserialize, Subcommand)] +#[clap(name = "config")] pub enum Config { /// Init `Dioxus.toml` for project/folder. Init { @@ -10,14 +11,14 @@ pub enum Config { name: String, /// Cover old config - #[structopt(long)] + #[clap(long)] #[serde(default)] force: bool, }, } impl Config { - pub fn config(self) -> anyhow::Result<()> { + pub fn config(self) -> Result<()> { let crate_root = crate::cargo::crate_root()?; match self { Config::Init { name, force } => { diff --git a/src/cli/create/mod.rs b/src/cli/create/mod.rs index b92a193b7..f00bc5dd9 100644 --- a/src/cli/create/mod.rs +++ b/src/cli/create/mod.rs @@ -1,15 +1,16 @@ use super::*; +use crate::custom_error; /// Build the Rust WASM app and all of its assets. -#[derive(Clone, Debug, Default, Deserialize, StructOpt)] -#[structopt(name = "create")] +#[derive(Clone, Debug, Default, Deserialize, Parser)] +#[clap(name = "create")] pub struct Create { /// Init project name - #[structopt(default_value = ".")] + #[clap(default_value = ".")] name: String, /// Template path - #[structopt(default_value = "gh:dioxuslabs/dioxus-template", long)] + #[clap(default_value = "gh:dioxuslabs/dioxus-template", long)] template: String, } @@ -23,10 +24,7 @@ impl Create { let project_path = PathBuf::from(&self.name); if project_path.join("Dioxus.toml").is_file() || project_path.join("Cargo.toml").is_file() { - return Err(Error::Other(anyhow::anyhow!( - "🧨 Folder '{}' is initialized.", - &self.name - ))); + return custom_error!("🧨 Folder '{}' is initialized.", &self.name); } log::info!("🔧 Start to create a new project '{}'.", self.name); @@ -47,9 +45,7 @@ impl Create { .stderr(Stdio::inherit()) .output()?; if !install_output.status.success() { - return Err(Error::Other(anyhow::anyhow!( - "Try to install cargo-generate failed." - ))); + return custom_error!("Try to install cargo-generate failed."); } } @@ -63,7 +59,7 @@ impl Create { .output()?; if !generate_output.status.success() { - return Err(Error::Other(anyhow::anyhow!("Generate project failed."))); + return custom_error!("Generate project failed."); } let mut dioxus_file = File::open(project_path.join("Dioxus.toml"))?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e3bd18b3b..8ec374933 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -6,31 +6,31 @@ pub mod create; pub mod serve; pub mod translate; -use std::{io::Write, path::PathBuf}; +use crate::custom_error; use crate::{cfg::ConfigOptsBuild, gen_page}; -use clap::{Parser}; +use crate::{cfg::ConfigOptsServe, server, CrateConfig}; +use crate::{error::Result, Error}; +use clap::Parser; +use html_parser::Dom; +use html_parser::Element; +use html_parser::Node; +use regex::Regex; use serde::Deserialize; +use std::fmt::{Display, Formatter}; +use std::fs::File; +use std::io::Read; +use std::process::exit; use std::{ fs::remove_dir_all, process::{Command, Stdio}, }; -use std::{fs::File}; -use std::{ - io::{Read}, -}; -use regex::Regex; -use crate::{error::Result, Error}; -use crate::{cfg::ConfigOptsServe, server, CrateConfig}; -use html_parser::Dom; -use html_parser::Element; -use html_parser::Node; -use std::fmt::{Display, Formatter}; -use std::process::exit; +use std::{io::Write, path::PathBuf}; +use clap::{Subcommand}; /// Build, bundle, & ship your Dioxus app. /// /// -#[derive(Parser, Debug)] +#[derive(Parser)] #[clap(name = "dioxus")] pub struct Cli { #[clap(subcommand)] @@ -42,7 +42,7 @@ pub struct Cli { // // // note: dioxus is still roughly compatible with trunk // /// Path to the Trunk config file [default: Trunk.toml] - // #[structopt(long, parse(from_os_str), env = "TRUNK_CONFIG")] + // #[clap(long, parse(from_os_str), env = "TRUNK_CONFIG")] // pub config: Option, } @@ -59,5 +59,6 @@ pub enum Commands { /// Clean output artifacts. Clean(clean::Clean), /// Dioxus config file controls. + #[clap(subcommand)] Config(config::Config), } diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index d7184f5f9..d627ace47 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -2,14 +2,14 @@ use super::*; /// Run the WASM project on dev-server #[derive(Clone, Debug, Parser)] -#[structopt(name = "serve")] +#[clap(name = "serve")] pub struct Serve { - #[structopt(flatten)] + #[clap(flatten)] pub serve: ConfigOptsServe, } impl Serve { - pub async fn serve(self) -> anyhow::Result<()> { + pub async fn serve(self) -> Result<()> { let mut crate_config = crate::CrateConfig::new()?; // change the relase state. @@ -49,7 +49,7 @@ impl Serve { return Ok(()); } _ => { - return Err(anyhow::anyhow!("Unsoppurt platform target.")); + return custom_error!("Unsoppurt platform target."); } } @@ -62,7 +62,7 @@ impl Serve { Ok(()) } - pub fn regen_dev_page(crate_config: &CrateConfig) -> anyhow::Result<()> { + pub fn regen_dev_page(crate_config: &CrateConfig) -> Result<()> { let serve_html = gen_page(&crate_config.dioxus_config, true); let mut file = std::fs::File::create( diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index 4e23533aa..55ba101cd 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -2,24 +2,24 @@ use super::*; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Parser)] -#[structopt(name = "translate")] +#[clap(name = "translate")] pub struct Translate { /// Activate debug mode // short and long flags (-d, --debug) will be deduced from the field's name - #[structopt(short, long)] + #[clap(short, long)] pub component: bool, /// Input file - #[structopt(short, long)] + #[clap(short, long)] pub file: Option, /// Output file, stdout if not present - #[structopt(parse(from_os_str))] + #[clap(parse(from_os_str))] pub output: Option, } impl Translate { - pub fn translate(self) -> anyhow::Result<()> { + pub fn translate(self) -> Result<()> { let Translate { component, output, diff --git a/src/error.rs b/src/error.rs index 8684abf74..d40868333 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,6 +11,15 @@ pub enum Error { #[error("I/O Error: {0}")] IO(#[from] std::io::Error), + #[error("Format Error: {0}")] + FormatError(#[from] std::fmt::Error), + + #[error("Format failed: {0}")] + ParseError(String), + + #[error("Runtime Error: {0}")] + RuntimeError(String), + #[error("Failed to write error")] FailedToWrite, @@ -20,6 +29,9 @@ pub enum Error { #[error("Failed to write error")] CargoError(String), + #[error("{0}")] + CustomError(String), + #[error(transparent)] Other(#[from] anyhow::Error), } @@ -35,3 +47,28 @@ impl From for Error { Error::Unique(s) } } + +impl From for Error { + fn from(e: html_parser::Error) -> Self { + Self::ParseError(e.to_string()) + } +} + +impl From for Error { + fn from(e: hyper::Error) -> Self { + Self::RuntimeError(e.to_string()) + } +} + +#[macro_export] +macro_rules! custom_error { + ($msg:literal $(,)?) => { + Err(Error::CustomError($msg.to_string())) + }; + ($err:expr $(,)?) => { + Err(Error::from($err)) + }; + ($fmt:expr, $($arg:tt)*) => { + Err(Error::CustomError(format!($fmt, $($arg)*))) + }; +} diff --git a/src/main.rs b/src/main.rs index 6b8c177db..97d4a3bb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ +use clap::Parser; use dioxus_cli::*; -use structopt::StructOpt; #[tokio::main] async fn main() -> Result<()> { - let args = Cli::from_args(); + let args = Cli::parse(); set_up_logging(); match args.action { diff --git a/src/server/mod.rs b/src/server/mod.rs index 880f25ceb..f312e07c2 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -10,6 +10,7 @@ use notify::{RecommendedWatcher, Watcher}; use std::{path::PathBuf, sync::Arc}; use tower_http::services::ServeDir; +use crate::Result; use crate::{builder, serve::Serve, CrateConfig}; use tokio::sync::broadcast; @@ -17,7 +18,7 @@ struct WsRelodState { update: broadcast::Sender, } -pub async fn startup(config: CrateConfig) -> anyhow::Result<()> { +pub async fn startup(config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); diff --git a/tests/main.rs b/tests/main.rs index f9bb6a890..1849f5dc8 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,4 +1,4 @@ -#[test] -fn ready() { - println!("Compiled successfully!") -} \ No newline at end of file +#[test] +fn ready() { + println!("Compiled successfully!") +} From 59ebb9ec116449bcd77ab554b34a6bb8e09796b9 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 9 Feb 2022 21:11:41 +0800 Subject: [PATCH 053/895] feat: add `default_platform` config --- src/assets/dioxus.toml | 15 ++++++++------- src/cli/build/mod.rs | 10 +++++++++- src/cli/cfg.rs | 12 ++++++------ src/cli/serve/mod.rs | 16 ++++++++++++++-- src/config.rs | 4 ++-- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 717b070e2..31e306079 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -1,23 +1,24 @@ [application] -# App (Project) Name +# dioxus project name name = "{{project-name}}" -# Dioxus App Support Platform -# desktop, web, mobile, ssr -platforms = ["web"] +# default platfrom +# you can also use `dioxus serve/build --platform XXX` to use other platform +# value: web | desktop +default_platform = "web" # Web `build` & `serve` dist path out_dir = "dist" +# resource (static) file folder +public_dir = "public" + [web.app] # HTML title tag content title = "dioxus | ⛺" -# resource (static) file folder -public_dir = "public" - [web.watcher] watch_path = ["src"] diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 684cec58c..bae291b7e 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -22,7 +22,15 @@ impl Build { crate_config.as_example(self.build.example.unwrap()); } - match self.build.platform.as_str() { + let platform = self.build.platform.unwrap_or_else(|| { + crate_config + .dioxus_config + .application + .default_platform + .clone() + }); + + match platform.as_str() { "web" => { crate::builder::build(&crate_config)?; } diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index ece00e07e..2271f0453 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -19,9 +19,9 @@ pub struct ConfigOptsBuild { #[structopt(long)] pub example: Option, - /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long, default_value = "web")] - pub platform: String, + /// Build platform: support Web & Desktop [default: "default_platform"] + #[structopt(long)] + pub platform: Option, } #[derive(Clone, Debug, Default, Deserialize, StructOpt)] @@ -39,9 +39,9 @@ pub struct ConfigOptsServe { #[serde(default)] pub release: bool, - /// Build platform: support Web & Desktop [default: "web"] - #[structopt(long, default_value = "web")] - pub platform: String, + /// Build platform: support Web & Desktop [default: "default_platform"] + #[structopt(long)] + pub platform: Option, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 8f26e0f30..ff263b6b5 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,5 +1,9 @@ use crate::{cfg::ConfigOptsServe, gen_page, server, CrateConfig}; -use std::{io::Write, path::PathBuf, process::{Command, Stdio}}; +use std::{ + io::Write, + path::PathBuf, + process::{Command, Stdio}, +}; use structopt::StructOpt; /// Run the WASM project on dev-server @@ -21,7 +25,15 @@ impl Serve { crate_config.as_example(self.serve.example.unwrap()); } - match self.serve.platform.as_str() { + let platform = self.serve.platform.unwrap_or_else(|| { + crate_config + .dioxus_config + .application + .default_platform + .clone() + }); + + match platform.as_str() { "web" => { crate::builder::build(&crate_config)?; } diff --git a/src/config.rs b/src/config.rs index 1151445ef..a7f5d1fec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -31,7 +31,7 @@ impl Default for DioxusConfig { Self { application: ApplicationConfig { name: "dioxus".into(), - platforms: vec![String::from("web")], + default_platform: "web".to_string(), out_dir: Some(PathBuf::from("dist")), }, web: WebConfig { @@ -59,7 +59,7 @@ impl Default for DioxusConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationConfig { pub name: String, - pub platforms: Vec, + pub default_platform: String, pub out_dir: Option, } From a0356c7f36cc8862ec3f49f92d07330070e3fa3e Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 9 Feb 2022 21:25:29 +0800 Subject: [PATCH 054/895] fix: clean `out_dir` --- src/builder.rs | 6 ++++-- src/cli/build/mod.rs | 2 +- src/cli/serve/mod.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 257072a6a..24168a934 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -120,7 +120,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { Ok(()) } -pub fn build_desktop(config: &CrateConfig) -> Result<()> { +pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { log::info!("🚅 Running build [Desktop] command..."); let mut cmd = Command::new("cargo"); @@ -146,7 +146,9 @@ pub fn build_desktop(config: &CrateConfig) -> Result<()> { } if output.status.success() { - if config.out_dir.is_dir() { + // this code will clean the output dir. + // if using the serve, we will not clean the out_dir. + if config.out_dir.is_dir() && !is_serve { remove_dir_all(&config.out_dir)?; } diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index bae291b7e..a29ba654b 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -35,7 +35,7 @@ impl Build { crate::builder::build(&crate_config)?; } "desktop" => { - crate::builder::build_desktop(&crate_config)?; + crate::builder::build_desktop(&crate_config, false)?; } _ => { return Err(anyhow::anyhow!("Unsoppurt platform target.")); diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index ff263b6b5..fe70f7914 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -38,7 +38,7 @@ impl Serve { crate::builder::build(&crate_config)?; } "desktop" => { - crate::builder::build_desktop(&crate_config)?; + crate::builder::build_desktop(&crate_config, true)?; match &crate_config.executable { crate::ExecutableType::Binary(name) From 653ee254c036653674a984cb716d0239c4c38f27 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 9 Feb 2022 21:30:00 +0800 Subject: [PATCH 055/895] docs: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bc1fa131..31e957111 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus proj ## Installation ``` -$ cargo install dioxus-cli +$ cargo install --git https://github.com/DioxusLabs/cli ``` Now, `dioxus` is in your path, you can use `dioxus --help` to get the help document. From 9d8b95dfc43023da050943300df86ba2612c72a6 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Wed, 9 Feb 2022 21:59:26 +0800 Subject: [PATCH 056/895] feat: add `public_dir` for other platform --- src/builder.rs | 31 ++++++++++++++++++++++++++++++- src/config.rs | 6 +++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 24168a934..1458d52ba 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -91,6 +91,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { .out_name(&dioxus_config.application.name) .generate(&bindgen_outdir)?; + // this code will copy all public file to the output dir let copy_options = fs_extra::dir::CopyOptions { overwrite: true, skip_exist: false, @@ -183,9 +184,37 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { file_name }; - create_dir_all(&config.out_dir)?; + if !config.out_dir.is_dir() { + create_dir_all(&config.out_dir)?; + } copy(res_path, &config.out_dir.join(target_file))?; + // this code will copy all public file to the output dir + if config.public_dir.is_dir() { + let copy_options = fs_extra::dir::CopyOptions { + overwrite: true, + skip_exist: false, + buffer_size: 64000, + copy_inside: false, + content_only: false, + depth: 0, + }; + + for entry in std::fs::read_dir(&config.public_dir)? { + let path = entry?.path(); + if path.is_file() { + std::fs::copy(&path, &config.out_dir.join(path.file_name().unwrap()))?; + } else { + match fs_extra::dir::copy(&path, &config.out_dir, ©_options) { + Ok(_) => {} + Err(e) => { + log::warn!("Error copying dir: {}", e); + } + } + } + } + } + log::info!( "🚩 Build completed: [./{}]", config diff --git a/src/config.rs b/src/config.rs index a7f5d1fec..5949310dd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,11 +33,11 @@ impl Default for DioxusConfig { name: "dioxus".into(), default_platform: "web".to_string(), out_dir: Some(PathBuf::from("dist")), + public_dir: Some(PathBuf::from("public")), }, web: WebConfig { app: WebAppConfing { title: Some("dioxus | ⛺".into()), - public_dir: Some(PathBuf::from("public")), }, watcher: WebWatcherConfing { watch_path: Some(vec![PathBuf::from("src")]), @@ -61,6 +61,7 @@ pub struct ApplicationConfig { pub name: String, pub default_platform: String, pub out_dir: Option, + pub public_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -73,7 +74,6 @@ pub struct WebConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfing { pub title: Option, - pub public_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -130,7 +130,7 @@ impl CrateConfig { let cargo_def = &crate_dir.join("Cargo.toml"); - let public_dir = match dioxus_config.web.app.public_dir { + let public_dir = match dioxus_config.application.public_dir { Some(ref v) => crate_dir.join(v), None => crate_dir.join("public"), }; From 62712219406ef95d83060bf637c0fa831bcc30d8 Mon Sep 17 00:00:00 2001 From: Aster Date: Thu, 10 Feb 2022 04:02:09 +0800 Subject: [PATCH 057/895] Fix format and clippy --- rustfmt.toml | 8 ++++++++ src/builder.rs | 12 +++++------- src/cli/config/mod.rs | 1 - src/cli/mod.rs | 32 +++++++++++++------------------- src/server/mod.rs | 3 +-- 5 files changed, 27 insertions(+), 29 deletions(-) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..9071fb4b5 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,8 @@ +version = "Two" +edition = "2018" + +imports_granularity = "Crate" +#use_small_heuristics = "Max" +#control_brace_style = "ClosingNextLine" +normalize_comments = true +format_code_in_doc_comments = true \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 257072a6a..f3090f85d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -11,13 +11,11 @@ use std::{ use wasm_bindgen_cli_support::Bindgen; pub fn build(config: &CrateConfig) -> Result<()> { - /* - [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) - [2] Generate the appropriate build folders - [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm - [4] Wasm-opt the .wasm file with whatever optimizations need to be done - [5] Link up the html page to the wasm module - */ + // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) + // [2] Generate the appropriate build folders + // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm + // [4] Wasm-opt the .wasm file with whatever optimizations need to be done + // [5] Link up the html page to the wasm module let CrateConfig { out_dir, diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 3cbf368e0..6d672b7a5 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -1,6 +1,5 @@ use super::*; - /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Deserialize, Subcommand)] #[clap(name = "config")] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 8ec374933..1b5ba0be7 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -6,30 +6,25 @@ pub mod create; pub mod serve; pub mod translate; -use crate::custom_error; -use crate::{cfg::ConfigOptsBuild, gen_page}; -use crate::{cfg::ConfigOptsServe, server, CrateConfig}; -use crate::{error::Result, Error}; -use clap::Parser; -use html_parser::Dom; -use html_parser::Element; -use html_parser::Node; +use crate::{ + cfg::{ConfigOptsBuild, ConfigOptsServe}, + custom_error, + error::Result, + gen_page, server, CrateConfig, Error, +}; +use clap::{Parser, Subcommand}; +use html_parser::{Dom, Element, Node}; use regex::Regex; use serde::Deserialize; -use std::fmt::{Display, Formatter}; -use std::fs::File; -use std::io::Read; -use std::process::exit; use std::{ - fs::remove_dir_all, - process::{Command, Stdio}, + fmt::{Display, Formatter}, + fs::{remove_dir_all, File}, + io::{Read, Write}, + path::PathBuf, + process::{exit, Command, Stdio}, }; -use std::{io::Write, path::PathBuf}; -use clap::{Subcommand}; /// Build, bundle, & ship your Dioxus app. -/// -/// #[derive(Parser)] #[clap(name = "dioxus")] pub struct Cli { @@ -39,7 +34,6 @@ pub struct Cli { /// Enable verbose logging. #[clap(short)] pub v: bool, - // // // note: dioxus is still roughly compatible with trunk // /// Path to the Trunk config file [default: Trunk.toml] // #[clap(long, parse(from_os_str), env = "TRUNK_CONFIG")] diff --git a/src/server/mod.rs b/src/server/mod.rs index f312e07c2..38e37d60b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -10,8 +10,7 @@ use notify::{RecommendedWatcher, Watcher}; use std::{path::PathBuf, sync::Arc}; use tower_http::services::ServeDir; -use crate::Result; -use crate::{builder, serve::Serve, CrateConfig}; +use crate::{builder, serve::Serve, CrateConfig, Result}; use tokio::sync::broadcast; struct WsRelodState { From 936fefbbf8da475d4b1a915c1d040161b9daee3c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Fri, 11 Feb 2022 16:54:35 +0800 Subject: [PATCH 058/895] feat: commit code --- src/builder.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 1458d52ba..c1e9fc0a7 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -5,6 +5,7 @@ use crate::{ }; use std::{ fs::{copy, create_dir_all, remove_dir_all}, + panic, path::PathBuf, process::Command, }; @@ -62,9 +63,6 @@ pub fn build(config: &CrateConfig) -> Result<()> { // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets").join("dioxus"); - // [3] Bindgen the final binary for use easy linking - let mut bindgen_builder = Bindgen::new(); - let release_type = match config.release { true => "release", false => "debug", @@ -80,16 +78,25 @@ pub fn build(config: &CrateConfig) -> Result<()> { .join(format!("{}.wasm", name)), }; - bindgen_builder - .input_path(input_path) - .web(true)? - .debug(true) - .demangle(true) - .keep_debug(true) - .remove_name_section(false) - .remove_producers_section(false) - .out_name(&dioxus_config.application.name) - .generate(&bindgen_outdir)?; + let bindgen_result = panic::catch_unwind(move || { + // [3] Bindgen the final binary for use easy linking + let mut bindgen_builder = Bindgen::new(); + + bindgen_builder + .input_path(input_path) + .web(true).unwrap() + .debug(true) + .demangle(true) + .keep_debug(true) + .remove_name_section(false) + .remove_producers_section(false) + .out_name(&dioxus_config.application.name) + .generate(&bindgen_outdir).unwrap(); + }); + if bindgen_result.is_err() { + panic!("Bindgen build failed"); + } + // this code will copy all public file to the output dir let copy_options = fs_extra::dir::CopyOptions { From c3ba5c287decc50d82748ee502de3bc863be04e8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Thu, 17 Feb 2022 19:28:54 +0800 Subject: [PATCH 059/895] feat: change public to `asset_dir` --- src/assets/dioxus.toml | 2 +- src/builder.rs | 10 +++++----- src/config.rs | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 31e306079..d3f160242 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -12,7 +12,7 @@ default_platform = "web" out_dir = "dist" # resource (static) file folder -public_dir = "public" +asset_dir = "public" [web.app] diff --git a/src/builder.rs b/src/builder.rs index efc5a915a..afd551dd3 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -22,7 +22,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { out_dir, crate_dir, target_dir, - public_dir, + asset_dir, executable, dioxus_config, .. @@ -105,8 +105,8 @@ pub fn build(config: &CrateConfig) -> Result<()> { content_only: false, depth: 0, }; - if public_dir.is_dir() { - for entry in std::fs::read_dir(&public_dir)? { + if asset_dir.is_dir() { + for entry in std::fs::read_dir(&asset_dir)? { let path = entry?.path(); if path.is_file() { std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?; @@ -195,7 +195,7 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { copy(res_path, &config.out_dir.join(target_file))?; // this code will copy all public file to the output dir - if config.public_dir.is_dir() { + if config.asset_dir.is_dir() { let copy_options = fs_extra::dir::CopyOptions { overwrite: true, skip_exist: false, @@ -205,7 +205,7 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { depth: 0, }; - for entry in std::fs::read_dir(&config.public_dir)? { + for entry in std::fs::read_dir(&config.asset_dir)? { let path = entry?.path(); if path.is_file() { std::fs::copy(&path, &config.out_dir.join(path.file_name().unwrap()))?; diff --git a/src/config.rs b/src/config.rs index 5949310dd..ba0427191 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,7 +33,7 @@ impl Default for DioxusConfig { name: "dioxus".into(), default_platform: "web".to_string(), out_dir: Some(PathBuf::from("dist")), - public_dir: Some(PathBuf::from("public")), + asset_dir: Some(PathBuf::from("public")), }, web: WebConfig { app: WebAppConfing { @@ -61,7 +61,7 @@ pub struct ApplicationConfig { pub name: String, pub default_platform: String, pub out_dir: Option, - pub public_dir: Option, + pub asset_dir: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -101,7 +101,7 @@ pub struct CrateConfig { pub crate_dir: PathBuf, pub workspace_dir: PathBuf, pub target_dir: PathBuf, - pub public_dir: PathBuf, + pub asset_dir: PathBuf, pub manifest: cargo_toml::Manifest, pub executable: ExecutableType, pub dioxus_config: DioxusConfig, @@ -130,7 +130,7 @@ impl CrateConfig { let cargo_def = &crate_dir.join("Cargo.toml"); - let public_dir = match dioxus_config.application.public_dir { + let asset_dir = match dioxus_config.application.asset_dir { Some(ref v) => crate_dir.join(v), None => crate_dir.join("public"), }; @@ -154,7 +154,7 @@ impl CrateConfig { crate_dir, workspace_dir, target_dir, - public_dir, + asset_dir, manifest, executable, release, From e7acc4d88de55792606014c28c9c235bdb860f41 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Thu, 17 Feb 2022 19:32:56 +0800 Subject: [PATCH 060/895] feat: add `log info` --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index afd551dd3..708e1ce69 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -92,7 +92,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { .generate(&bindgen_outdir).unwrap(); }); if bindgen_result.is_err() { - panic!("Bindgen build failed"); + log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate."); } From 8a0abec82865daf78c5783d897c4d8375c0fbb6c Mon Sep 17 00:00:00 2001 From: YuKun Liu Date: Fri, 18 Feb 2022 09:50:26 +0800 Subject: [PATCH 061/895] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 33d1d4932..a939dfcaf 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ dioxus 0.1.2 Build, bundle, & ship your Dioxus app USAGE: - dioxus.exe [FLAGS] + dioxus [FLAGS] FLAGS: -h, --help Prints help information @@ -42,10 +42,10 @@ SUBCOMMANDS: ## Get Started -You can use the `dioxus crate project_name` to init a dioxus project, its will be clone from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template). +You can use the `dioxus create project_name` to init a dioxus project, its will be clone from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template). or you can assign the template path: ``` dioxus create hello --template gh:dioxuslabs/dioxus-template -``` \ No newline at end of file +``` From d462e032925f3a455eb0808274df69207f057fd5 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 18 Feb 2022 15:40:16 -0500 Subject: [PATCH 062/895] fix: indenting --- src/cli/translate/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index a717d632a..3e1f1057c 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -23,7 +23,7 @@ pub struct Translate { pub file: Option, /// Output file, stdout if not present - #[structopt(parse(from_os_str))] + #[structopt(short, long)] pub output: Option, } @@ -176,6 +176,7 @@ fn component(cx: Scope) -> Element {{ } writeln!(f, "\n\nmod icons {{")?; + writeln!(f, "\tuse super::*;")?; let mut id = 0; while let Some(svg) = svg_nodes.pop() { @@ -188,7 +189,8 @@ fn component(cx: Scope) -> Element {{ write_tabs(f, 3)?; render_element(f, svg, 3, &mut svg_nodes, false, &mut 0)?; - writeln!(f, "\t\t))\n\t}}\n")?; + + writeln!(f, "\t\t))\n\t}}")?; id += 1; } From 91a8ce31690d54b8df896254e58206da2816b0cd Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Thu, 10 Mar 2022 11:29:27 +0800 Subject: [PATCH 063/895] feat: config init `platform` arg --- src/assets/autoreload.js | 4 +++- src/assets/dioxus.toml | 2 +- src/cli/config/mod.rs | 13 +++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js index da62e5eae..fffb3e26c 100644 --- a/src/assets/autoreload.js +++ b/src/assets/autoreload.js @@ -1,3 +1,6 @@ +// Dioxus-CLI +// https://github.com/DioxusLabs/cli + (function () { var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; var url = protocol + '//' + window.location.host + '/_dioxus/ws'; @@ -15,7 +18,6 @@ var ws = new WebSocket(url); ws.onmessage = (ev) => { if (ev.data == "reload") { - // alert("reload!!!"); window.location.reload(); } }; diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index d3f160242..af9cc886b 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -6,7 +6,7 @@ name = "{{project-name}}" # default platfrom # you can also use `dioxus serve/build --platform XXX` to use other platform # value: web | desktop -default_platform = "web" +default_platform = "{{default-platform}}" # Web `build` & `serve` dist path out_dir = "dist" diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 6d672b7a5..2a1f28fda 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -13,6 +13,10 @@ pub enum Config { #[clap(long)] #[serde(default)] force: bool, + + /// Project default platform + #[clap(long, default_value = "web")] + platform: String, }, } @@ -20,7 +24,11 @@ impl Config { pub fn config(self) -> Result<()> { let crate_root = crate::cargo::crate_root()?; match self { - Config::Init { name, force } => { + Config::Init { + name, + force, + platform, + } => { let conf_path = crate_root.join("Dioxus.toml"); if conf_path.is_file() && !force { log::warn!( @@ -30,7 +38,8 @@ impl Config { } let mut file = File::create(conf_path)?; let content = String::from(include_str!("../../assets/dioxus.toml")) - .replace("{{project-name}}", &name); + .replace("{{project-name}}", &name) + .replace("{{default-platform}}", &platform); file.write_all(content.as_bytes())?; log::info!("🚩 Init config file completed."); } From 5fb1b3e20bb5f8282c735bcf7160dfdbcaf695d9 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sat, 12 Mar 2022 13:00:07 +0800 Subject: [PATCH 064/895] feat: commit code --- Cargo.toml | 7 ++++- src/assets/dioxus.toml | 4 ++- src/cli/mod.rs | 1 + src/cli/tools.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/cli/tools.rs diff --git a/Cargo.toml b/Cargo.toml index 3ae7b4610..6a7a2c9d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,12 @@ license = "MIT/Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + # cli core clap = {version = "3.0.14", features = ["derive"]} thiserror = "1.0.30" wasm-bindgen-cli-support = "0.2.79" + # features log = "0.4.14" fern = { version = "0.6.0", features = ["colored"] } @@ -37,7 +39,10 @@ hyper = "0.14.17" axum = { version = "0.4.5", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } headers = "0.3.7" -# hyper = { version = "0.14.11", features = ["full"] } + +# tools download +dirs = "4.0.0" +reqwest = { version = "0.11", features = ["json"] } [[bin]] path = "src/main.rs" diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index af9cc886b..b897a39a7 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -36,4 +36,6 @@ script = [] # Javascript code file # serve: [dev-server] only -script = [] \ No newline at end of file +script = [] + +[web.tools] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1b5ba0be7..9f31c60ae 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -5,6 +5,7 @@ pub mod config; pub mod create; pub mod serve; pub mod translate; +pub mod tools; use crate::{ cfg::{ConfigOptsBuild, ConfigOptsServe}, diff --git a/src/cli/tools.rs b/src/cli/tools.rs new file mode 100644 index 000000000..aa320275e --- /dev/null +++ b/src/cli/tools.rs @@ -0,0 +1,69 @@ +use std::path::PathBuf; + +pub enum Tool { + WasmOpt, +} + +pub fn app_path() { + let data_local = dirs::data_local_dir().unwrap(); + +} + +impl Tool { + pub fn name(&self) -> &str { + match self { + Self::WasmOpt => "wasm-opt", + } + } + + pub fn bin_path(&self) -> &str { + if cfg!(target_os = "windows") { + match self { + Self::WasmOpt => "bin/wasm-opt.exe", + } + } else { + match self { + Self::WasmOpt => "bin/wasm-opt", + } + } + } + + pub fn target_platform(&self) -> &str { + match self { + Self::WasmOpt => { + if cfg!(target_os = "windows") { + "windows" + } else if cfg!(target_os = "macos") { + "macos" + } else if cfg!(target_os = "linux") { + "linux" + } else { + panic!("unsupported platformm"); + } + } + } + } + + pub fn download_url(&self) -> String { + match self { + Self::WasmOpt => { + format!( + "https://github.com/WebAssembly/binaryen/releases/download/version_105/binaryen-version_105-x86_64-{target}.tar.gz", + target = self.target_platform() + ) + } + } + } + + pub async fn download_package(&self) { + + let download_dir = dirs::download_dir().unwrap(); + let download_url = self.download_url(); + + let resp = reqwest::get(download_url).await.unwrap(); + + resp. + + } + +} From 25ff6c5937b8907a734d05b6936f5f20e8113b5b Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sat, 12 Mar 2022 23:48:05 +0800 Subject: [PATCH 065/895] feat: commit code --- Cargo.toml | 2 +- src/cli/tools.rs | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6a7a2c9d0..0b96d72a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ headers = "0.3.7" # tools download dirs = "4.0.0" -reqwest = { version = "0.11", features = ["json"] } +reqwest = { version = "0.11", features = ["rustls-tls", "stream", "trust-dns"] } [[bin]] path = "src/main.rs" diff --git a/src/cli/tools.rs b/src/cli/tools.rs index aa320275e..a042e7565 100644 --- a/src/cli/tools.rs +++ b/src/cli/tools.rs @@ -1,12 +1,29 @@ -use std::path::PathBuf; +use std::{fs::create_dir_all, path::PathBuf}; + +use anyhow::Context; +use futures::StreamExt; +use tokio::io::AsyncWriteExt; pub enum Tool { WasmOpt, } -pub fn app_path() { +pub fn app_path() -> PathBuf { let data_local = dirs::data_local_dir().unwrap(); - + let dioxus_dir = data_local.join("dioxus"); + if !dioxus_dir.is_dir() { + create_dir_all(&dioxus_dir).unwrap(); + } + dioxus_dir +} + +pub fn temp_path() -> PathBuf { + let app_path = app_path(); + let temp_path = app_path.join("temp"); + if !temp_path.is_dir() { + create_dir_all(&temp_path).unwrap(); + } + temp_path } impl Tool { @@ -55,15 +72,23 @@ impl Tool { } } - pub async fn download_package(&self) { - - let download_dir = dirs::download_dir().unwrap(); + pub async fn download_package(&self) -> anyhow::Result { + let temp_dir = temp_path(); let download_url = self.download_url(); + let temp_out = temp_dir.join(format!("{}-tool.tmp", self.name())); + let mut file = tokio::fs::File::create(&temp_out) + .await + .context("failed creating temporary output file")?; + let resp = reqwest::get(download_url).await.unwrap(); - resp. + let mut res_bytes = resp.bytes_stream(); + while let Some(chunk_res) = res_bytes.next().await { + let chunk = chunk_res.context("error reading chunk from download")?; + let _ = file.write(chunk.as_ref()).await; + } + Ok(temp_out) } - } From eea01f7f8c94c00d6c8ae4cbe6bde29e184552a6 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 13 Mar 2022 13:19:54 +0800 Subject: [PATCH 066/895] feat: commit code --- Cargo.toml | 2 ++ src/cli/mod.rs | 4 ++++ src/cli/tool/mod.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/cli/tools.rs | 45 +++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 6 ++++++ 5 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 src/cli/tool/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 0b96d72a2..8beca8f7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ headers = "0.3.7" # tools download dirs = "4.0.0" reqwest = { version = "0.11", features = ["rustls-tls", "stream", "trust-dns"] } +flate2 = "1.0.22" +tar = "0.4.38" [[bin]] path = "src/main.rs" diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9f31c60ae..6e653507d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -6,6 +6,7 @@ pub mod create; pub mod serve; pub mod translate; pub mod tools; +pub mod tool; use crate::{ cfg::{ConfigOptsBuild, ConfigOptsServe}, @@ -56,4 +57,7 @@ pub enum Commands { /// Dioxus config file controls. #[clap(subcommand)] Config(config::Config), + /// Install & Manage tools for Dioxus-cli. + #[clap(subcommand)] + Tool(tool::Tool), } diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs new file mode 100644 index 000000000..3f3a86bfc --- /dev/null +++ b/src/cli/tool/mod.rs @@ -0,0 +1,40 @@ +use super::*; + +/// Build the Rust WASM app and all of its assets. +#[derive(Clone, Debug, Deserialize, Subcommand)] +#[clap(name = "tool")] +pub enum Tool { + /// Return all dioxus-cli support tools. + List {}, + Add { + name: String + } +} + +impl Tool { + pub async fn tool(self) -> Result<()> { + match self { + Tool::List {} => { + for item in tools::tool_list() { + if tools::Tool::from_str(item).unwrap().is_installed() { + println!("{item} [installed]"); + } else { + println!("{item}"); + } + } + } + Tool::Add { name } => { + let tool_list = tools::tool_list(); + + if !tool_list.contains(&name.as_str()) { + log::error!("Tool {name} not found."); + return Ok(()); + } + let target_tool = tools::Tool::from_str(&name).unwrap(); + println!("{:?}", target_tool.download_package().await); + } + } + + Ok(()) + } +} diff --git a/src/cli/tools.rs b/src/cli/tools.rs index a042e7565..1eb68e773 100644 --- a/src/cli/tools.rs +++ b/src/cli/tools.rs @@ -8,6 +8,10 @@ pub enum Tool { WasmOpt, } +pub fn tool_list() -> Vec<&'static str> { + vec!["wasm-opt"] +} + pub fn app_path() -> PathBuf { let data_local = dirs::data_local_dir().unwrap(); let dioxus_dir = data_local.join("dioxus"); @@ -26,7 +30,24 @@ pub fn temp_path() -> PathBuf { temp_path } +pub fn tools_path(tool: &Tool) -> PathBuf { + let app_path = app_path(); + let temp_path = app_path.join("tools"); + if !temp_path.is_dir() { + create_dir_all(&temp_path).unwrap(); + } + temp_path.join(tool.name()) +} + +#[allow(clippy::should_implement_trait)] impl Tool { + pub fn from_str(name: &str) -> Option { + match name { + "wasm-opt" => Some(Self::WasmOpt), + _ => None, + } + } + pub fn name(&self) -> &str { match self { Self::WasmOpt => "wasm-opt", @@ -72,11 +93,23 @@ impl Tool { } } - pub async fn download_package(&self) -> anyhow::Result { - let temp_dir = temp_path(); - let download_url = self.download_url(); + pub fn extension(&self) -> &str { + match self { + Self::WasmOpt => "tar.gz", + } + } - let temp_out = temp_dir.join(format!("{}-tool.tmp", self.name())); + pub fn is_installed(&self) -> bool { + tools_path(self).is_dir() + } + + pub fn temp_out_path(&self) -> PathBuf { + temp_path().join(format!("{}-tool.tmp", self.name())) + } + + pub async fn download_package(&self) -> anyhow::Result { + let download_url = self.download_url(); + let temp_out = self.temp_out_path(); let mut file = tokio::fs::File::create(&temp_out) .await .context("failed creating temporary output file")?; @@ -91,4 +124,8 @@ impl Tool { Ok(temp_out) } + + pub async fn install_package() -> anyhow::Result<()> { + Ok(()) + } } diff --git a/src/main.rs b/src/main.rs index 97d4a3bb4..099ff74c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,12 @@ async fn main() -> Result<()> { log::error!("config error: {}", e); } } + + Commands::Tool(opts) => { + if let Err(e) = opts.tool().await { + log::error!("tool error: {}", e); + } + } } Ok(()) From 140d7ad7ed1b724b19806ea8999bde84b904646d Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 14 Mar 2022 19:11:12 +0800 Subject: [PATCH 067/895] feat: commit code --- Dioxus.toml | 45 +++++++++++++++++++++++++++++++ src/assets/dioxus.toml | 6 ++++- src/cli/config/mod.rs | 5 ++++ src/cli/tool/mod.rs | 26 +++++++++++++++++- src/cli/tools.rs | 61 ++++++++++++++++++++++++++++-------------- src/config.rs | 4 ++- 6 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 Dioxus.toml diff --git a/Dioxus.toml b/Dioxus.toml new file mode 100644 index 000000000..ab85abe86 --- /dev/null +++ b/Dioxus.toml @@ -0,0 +1,45 @@ +[application] + +# dioxus project name +name = "{{project-name}}" + +# default platfrom +# you can also use `dioxus serve/build --platform XXX` to use other platform +# value: web | desktop +default_platform = "{{default-platform}}" + +# Web `build` & `serve` dist path +out_dir = "dist" + +# resource (static) file folder +asset_dir = "public" + +[web.app] + +# HTML title tag content +title = "dioxus | ⛺" + +[web.watcher] + +watch_path = ["src"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [] + +[application.tools] + +# use binaryen.wasm-opt for output Wasm file +# binaryen just will trigger in `web` platform +binaryen = { wasm_opt = [".PROJECT_OUT"] } \ No newline at end of file diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index b897a39a7..ab85abe86 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -38,4 +38,8 @@ script = [] # serve: [dev-server] only script = [] -[web.tools] +[application.tools] + +# use binaryen.wasm-opt for output Wasm file +# binaryen just will trigger in `web` platform +binaryen = { wasm_opt = [".PROJECT_OUT"] } \ No newline at end of file diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 2a1f28fda..6422ede27 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -18,6 +18,8 @@ pub enum Config { #[clap(long, default_value = "web")] platform: String, }, + /// Format Print Dioxus-Config. + FormatPrint {} } impl Config { @@ -43,6 +45,9 @@ impl Config { file.write_all(content.as_bytes())?; log::info!("🚩 Init config file completed."); } + Config::FormatPrint {} => { + println!("{:#?}", crate::CrateConfig::new()?.dioxus_config); + } } Ok(()) } diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index 3f3a86bfc..1b8768497 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -6,6 +6,9 @@ use super::*; pub enum Tool { /// Return all dioxus-cli support tools. List {}, + /// Get default app install path. + AppPath {}, + /// Install a new tool. Add { name: String } @@ -23,6 +26,9 @@ impl Tool { } } } + Tool::AppPath {} => { + println!("{}", tools::tools_path().to_str().unwrap()); + } Tool::Add { name } => { let tool_list = tools::tool_list(); @@ -31,7 +37,25 @@ impl Tool { return Ok(()); } let target_tool = tools::Tool::from_str(&name).unwrap(); - println!("{:?}", target_tool.download_package().await); + + if target_tool.is_installed() { + log::warn!("Tool {name} is installed."); + return Ok(()); + } + + log::info!("Start to download tool package..."); + if let Err(e) = target_tool.download_package().await { + log::error!("Tool download failed: {e}"); + return Ok(()); + } + + log::info!("Start to install tool package..."); + if let Err(e) = target_tool.install_package().await { + log::error!("Tool install failed: {e}"); + return Ok(()); + } + + log::info!("Tool {name} install successfully!"); } } diff --git a/src/cli/tools.rs b/src/cli/tools.rs index 1eb68e773..257c7f856 100644 --- a/src/cli/tools.rs +++ b/src/cli/tools.rs @@ -1,15 +1,21 @@ -use std::{fs::create_dir_all, path::PathBuf}; +use std::{ + fs::{create_dir_all, File}, + path::PathBuf, +}; use anyhow::Context; +use flate2::read::GzDecoder; use futures::StreamExt; +use tar::Archive; use tokio::io::AsyncWriteExt; +#[derive(Debug, PartialEq, Eq)] pub enum Tool { - WasmOpt, + Binaryen, } pub fn tool_list() -> Vec<&'static str> { - vec!["wasm-opt"] + vec!["binaryen"] } pub fn app_path() -> PathBuf { @@ -30,45 +36,39 @@ pub fn temp_path() -> PathBuf { temp_path } -pub fn tools_path(tool: &Tool) -> PathBuf { +pub fn tools_path() -> PathBuf { let app_path = app_path(); let temp_path = app_path.join("tools"); if !temp_path.is_dir() { create_dir_all(&temp_path).unwrap(); } - temp_path.join(tool.name()) + temp_path } #[allow(clippy::should_implement_trait)] impl Tool { pub fn from_str(name: &str) -> Option { match name { - "wasm-opt" => Some(Self::WasmOpt), + "binaryen" => Some(Self::Binaryen), _ => None, } } pub fn name(&self) -> &str { match self { - Self::WasmOpt => "wasm-opt", + Self::Binaryen => "binaryen", } } pub fn bin_path(&self) -> &str { - if cfg!(target_os = "windows") { - match self { - Self::WasmOpt => "bin/wasm-opt.exe", - } - } else { - match self { - Self::WasmOpt => "bin/wasm-opt", - } + match self { + Self::Binaryen => "bin", } } pub fn target_platform(&self) -> &str { match self { - Self::WasmOpt => { + Self::Binaryen => { if cfg!(target_os = "windows") { "windows" } else if cfg!(target_os = "macos") { @@ -84,7 +84,7 @@ impl Tool { pub fn download_url(&self) -> String { match self { - Self::WasmOpt => { + Self::Binaryen => { format!( "https://github.com/WebAssembly/binaryen/releases/download/version_105/binaryen-version_105-x86_64-{target}.tar.gz", target = self.target_platform() @@ -95,12 +95,12 @@ impl Tool { pub fn extension(&self) -> &str { match self { - Self::WasmOpt => "tar.gz", + Self::Binaryen => "tar.gz", } } pub fn is_installed(&self) -> bool { - tools_path(self).is_dir() + tools_path().join(self.name()).is_dir() } pub fn temp_out_path(&self) -> PathBuf { @@ -125,7 +125,28 @@ impl Tool { Ok(temp_out) } - pub async fn install_package() -> anyhow::Result<()> { + pub async fn install_package(&self) -> anyhow::Result<()> { + let temp_path = self.temp_out_path(); + let tool_path = tools_path(); + + let dir_name = if self == &Tool::Binaryen { + "binaryen-version_105" + } else { + "" + }; + + if self.extension() == "tar.gz" { + let tar_gz = File::open(temp_path)?; + let tar = GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + archive.unpack(&tool_path)?; + // println!("{:?} -> {:?}", tool_path.join(dir_name), tool_path.join(self.name())); + std::fs::rename( + tool_path.join(dir_name), + tool_path.join(self.name()), + )?; + } + Ok(()) } } diff --git a/src/config.rs b/src/config.rs index ba0427191..f7897f5f8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use crate::error::Result; use serde::{Deserialize, Serialize}; -use std::{fs::File, io::Read, path::PathBuf}; +use std::{fs::File, io::Read, path::PathBuf, collections::HashMap}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DioxusConfig { @@ -34,6 +34,7 @@ impl Default for DioxusConfig { default_platform: "web".to_string(), out_dir: Some(PathBuf::from("dist")), asset_dir: Some(PathBuf::from("public")), + tools: None, }, web: WebConfig { app: WebAppConfing { @@ -62,6 +63,7 @@ pub struct ApplicationConfig { pub default_platform: String, pub out_dir: Option, pub asset_dir: Option, + pub tools: Option> } #[derive(Debug, Clone, Serialize, Deserialize)] From 2e83822d415e8d29503defb56eec5cccb0231ed3 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Mon, 14 Mar 2022 22:39:15 +0800 Subject: [PATCH 068/895] feat: commit code --- Dioxus.toml | 4 ++-- src/cli/mod.rs | 1 - src/cli/tool/mod.rs | 2 ++ src/lib.rs | 2 ++ src/{cli => }/tools.rs | 11 +++++++++++ 5 files changed, 17 insertions(+), 3 deletions(-) rename src/{cli => }/tools.rs (92%) diff --git a/Dioxus.toml b/Dioxus.toml index ab85abe86..2db611914 100644 --- a/Dioxus.toml +++ b/Dioxus.toml @@ -1,12 +1,12 @@ [application] # dioxus project name -name = "{{project-name}}" +name = "dioxus-cli" # default platfrom # you can also use `dioxus serve/build --platform XXX` to use other platform # value: web | desktop -default_platform = "{{default-platform}}" +default_platform = "desktop" # Web `build` & `serve` dist path out_dir = "dist" diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6e653507d..2c91c94dd 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -5,7 +5,6 @@ pub mod config; pub mod create; pub mod serve; pub mod translate; -pub mod tools; pub mod tool; use crate::{ diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index 1b8768497..51e41e384 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -1,3 +1,5 @@ +use crate::tools; + use super::*; /// Build the Rust WASM app and all of its assets. diff --git a/src/lib.rs b/src/lib.rs index 395cbc8dc..8cd4b1f2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ pub mod builder; pub mod server; +pub mod tools; + pub use builder::*; pub mod cargo; diff --git a/src/cli/tools.rs b/src/tools.rs similarity index 92% rename from src/cli/tools.rs rename to src/tools.rs index 257c7f856..b5c9d658a 100644 --- a/src/cli/tools.rs +++ b/src/tools.rs @@ -47,6 +47,8 @@ pub fn tools_path() -> PathBuf { #[allow(clippy::should_implement_trait)] impl Tool { + + /// from str to tool enum pub fn from_str(name: &str) -> Option { match name { "binaryen" => Some(Self::Binaryen), @@ -54,18 +56,21 @@ impl Tool { } } + /// get current tool name str pub fn name(&self) -> &str { match self { Self::Binaryen => "binaryen", } } + /// get tool bin dir path pub fn bin_path(&self) -> &str { match self { Self::Binaryen => "bin", } } + /// get target platform pub fn target_platform(&self) -> &str { match self { Self::Binaryen => { @@ -82,6 +87,7 @@ impl Tool { } } + /// get tool package download url pub fn download_url(&self) -> String { match self { Self::Binaryen => { @@ -93,20 +99,24 @@ impl Tool { } } + /// get package extension name pub fn extension(&self) -> &str { match self { Self::Binaryen => "tar.gz", } } + /// check tool state pub fn is_installed(&self) -> bool { tools_path().join(self.name()).is_dir() } + /// get download temp path pub fn temp_out_path(&self) -> PathBuf { temp_path().join(format!("{}-tool.tmp", self.name())) } + /// start to download package pub async fn download_package(&self) -> anyhow::Result { let download_url = self.download_url(); let temp_out = self.temp_out_path(); @@ -125,6 +135,7 @@ impl Tool { Ok(temp_out) } + /// start to install package pub async fn install_package(&self) -> anyhow::Result<()> { let temp_path = self.temp_out_path(); let tool_path = tools_path(); From 3514e341124bd9f0b9f91ad6604c071cd9296685 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 15 Mar 2022 00:22:41 +0800 Subject: [PATCH 069/895] feat: commit code --- Dioxus.toml | 2 +- src/builder.rs | 27 +++++++++++++++++++++++++-- src/cli/build/mod.rs | 1 + src/tools.rs | 34 +++++++++++++++++++++++++++++----- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Dioxus.toml b/Dioxus.toml index 2db611914..c3e0dd8a0 100644 --- a/Dioxus.toml +++ b/Dioxus.toml @@ -42,4 +42,4 @@ script = [] # use binaryen.wasm-opt for output Wasm file # binaryen just will trigger in `web` platform -binaryen = { wasm_opt = [".PROJECT_OUT"] } \ No newline at end of file +binaryen = { wasm_opt = true } \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 708e1ce69..870e737f0 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -82,19 +82,42 @@ pub fn build(config: &CrateConfig) -> Result<()> { bindgen_builder .input_path(input_path) - .web(true).unwrap() + .web(true) + .unwrap() .debug(true) .demangle(true) .keep_debug(true) .remove_name_section(false) .remove_producers_section(false) .out_name(&dioxus_config.application.name) - .generate(&bindgen_outdir).unwrap(); + .generate(&bindgen_outdir) + .unwrap(); }); if bindgen_result.is_err() { log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate."); } + // check binaryen:wasm-opt tool + let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default(); + if dioxus_tools.contains_key("binaryen") { + let info = dioxus_tools.get("binaryen").unwrap(); + let binaryen = crate::tools::Tool::Binaryen; + if let Some(sub) = info.as_table() { + println!("sub: {sub:?}"); + if sub.contains_key("wasm_opt") + && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false) + { + let target_file = out_dir + .join("assets") + .join("dioxus") + .join(format!("{}_bg.wasm", dioxus_config.application.name)); + println!("tf: {target_file:?}"); + if target_file.is_file() { + binaryen.call("wasm-opt", vec![target_file.to_str().unwrap(), "--print"])?; + } + } + } + } // this code will copy all public file to the output dir let copy_options = fs_extra::dir::CopyOptions { diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 4c043091f..3b4d343af 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -12,6 +12,7 @@ impl Build { pub fn build(self) -> Result<()> { let mut crate_config = crate::CrateConfig::new()?; + // change the release state. crate_config.with_release(self.build.release); diff --git a/src/tools.rs b/src/tools.rs index b5c9d658a..b84cd5579 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -1,6 +1,7 @@ use std::{ fs::{create_dir_all, File}, path::PathBuf, + process::Command, }; use anyhow::Context; @@ -47,7 +48,6 @@ pub fn tools_path() -> PathBuf { #[allow(clippy::should_implement_trait)] impl Tool { - /// from str to tool enum pub fn from_str(name: &str) -> Option { match name { @@ -152,12 +152,36 @@ impl Tool { let mut archive = Archive::new(tar); archive.unpack(&tool_path)?; // println!("{:?} -> {:?}", tool_path.join(dir_name), tool_path.join(self.name())); - std::fs::rename( - tool_path.join(dir_name), - tool_path.join(self.name()), - )?; + std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?; } Ok(()) } + + 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() + } + } + }; + + if !bin_path.join(command_file).is_file() { + return Err(anyhow::anyhow!("Command file not found.")); + } + + let mut command = Command::new(bin_path.to_str().unwrap()); + + command + .args(&args[..]) + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()); + + Ok(()) + } } From 62a2292c16e54fe46c1438d7629ed67831eb5018 Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 15 Mar 2022 17:32:42 +0800 Subject: [PATCH 070/895] feat: commit code --- src/builder.rs | 18 +++++++++++++++--- src/tools.rs | 14 +++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 870e737f0..ac9f72b13 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -95,6 +95,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { }); if bindgen_result.is_err() { log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate."); + return Ok(()); } // check binaryen:wasm-opt tool @@ -102,8 +103,13 @@ pub fn build(config: &CrateConfig) -> Result<()> { if dioxus_tools.contains_key("binaryen") { let info = dioxus_tools.get("binaryen").unwrap(); let binaryen = crate::tools::Tool::Binaryen; + + if !binaryen.is_installed() { + log::error!("Binaryen tool not found, you can use `dioxus tool add binaryen` to install it."); + return Ok(()); + } + if let Some(sub) = info.as_table() { - println!("sub: {sub:?}"); if sub.contains_key("wasm_opt") && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false) { @@ -111,9 +117,15 @@ pub fn build(config: &CrateConfig) -> Result<()> { .join("assets") .join("dioxus") .join(format!("{}_bg.wasm", dioxus_config.application.name)); - println!("tf: {target_file:?}"); if target_file.is_file() { - binaryen.call("wasm-opt", vec![target_file.to_str().unwrap(), "--print"])?; + binaryen.call( + "wasm-opt", + vec![ + target_file.to_str().unwrap(), + "-o", + target_file.to_str().unwrap(), + ], + )?; } } } diff --git a/src/tools.rs b/src/tools.rs index b84cd5579..937063be0 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -158,7 +158,7 @@ impl Tool { Ok(()) } - pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result<()> { + 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 { @@ -171,17 +171,17 @@ impl Tool { } }; - if !bin_path.join(command_file).is_file() { + if !bin_path.join(&command_file).is_file() { return Err(anyhow::anyhow!("Command file not found.")); } - let mut command = Command::new(bin_path.to_str().unwrap()); + let mut command = Command::new(bin_path.join(&command_file).to_str().unwrap()); - command + let output = command .args(&args[..]) .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()); - - Ok(()) + .stderr(std::process::Stdio::inherit()) + .output()?; + Ok(output.stdout) } } From 8b380f2617f3845db6d7006790312290c85cf19c Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Tue, 15 Mar 2022 18:28:19 +0800 Subject: [PATCH 071/895] feat: commit code --- src/builder.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index ac9f72b13..d58af6f43 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -105,29 +105,30 @@ pub fn build(config: &CrateConfig) -> Result<()> { let binaryen = crate::tools::Tool::Binaryen; if !binaryen.is_installed() { - log::error!("Binaryen tool not found, you can use `dioxus tool add binaryen` to install it."); - return Ok(()); - } - - if let Some(sub) = info.as_table() { - if sub.contains_key("wasm_opt") - && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false) - { - let target_file = out_dir - .join("assets") - .join("dioxus") - .join(format!("{}_bg.wasm", dioxus_config.application.name)); - if target_file.is_file() { - binaryen.call( - "wasm-opt", - vec![ - target_file.to_str().unwrap(), - "-o", - target_file.to_str().unwrap(), - ], - )?; + if let Some(sub) = info.as_table() { + if sub.contains_key("wasm_opt") + && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false) + { + let target_file = out_dir + .join("assets") + .join("dioxus") + .join(format!("{}_bg.wasm", dioxus_config.application.name)); + if target_file.is_file() { + binaryen.call( + "wasm-opt", + vec![ + target_file.to_str().unwrap(), + "-o", + target_file.to_str().unwrap(), + ], + )?; + } } } + } else { + log::warn!( + "Binaryen tool not found, you can use `dioxus tool add binaryen` to install it." + ); } } From 6b0d57abe5c70ebd8cc7cdcc9f14fea5c8b738dd Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 20 Mar 2022 18:39:28 +0800 Subject: [PATCH 072/895] feat: commit code --- Cargo.toml | 2 +- src/server/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8beca8f7d..246e90517 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dioxus-cli" -version = "0.1.3" +version = "0.1.4" authors = ["Jonathan Kelley"] edition = "2018" description = "CLI tool for developing, testing, and publishing Dioxus apps" diff --git a/src/server/mod.rs b/src/server/mod.rs index 38e37d60b..7d63f3eb6 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -33,6 +33,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { // file watcher: check file change let watcher_conf = config.clone(); let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { + log::info!("Start to rebuild project..."); if chrono::Local::now().timestamp() > last_update_time && builder::build(&watcher_conf).is_ok() { @@ -47,8 +48,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { { let _ = Serve::regen_dev_page(&watcher_conf); } - println!("watcher send reload"); - reload_tx.send("reload".into()).unwrap(); + let _ = reload_tx.send("reload".into()); last_update_time = chrono::Local::now().timestamp(); } }) From e5dfe84eb1f8c821fa875744ed7ec541de8013ad Mon Sep 17 00:00:00 2001 From: mrxiaozhuox Date: Sun, 20 Mar 2022 19:31:30 +0800 Subject: [PATCH 073/895] feat: add `custom html` support --- src/assets/index.html | 2 -- src/builder.rs | 17 +++++++++++++++-- src/cli/config/mod.rs | 13 +++++++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/assets/index.html b/src/assets/index.html index 9934e490d..925df0227 100644 --- a/src/assets/index.html +++ b/src/assets/index.html @@ -4,11 +4,9 @@ {style_include} -
- {script_include} From 4867cb5cf30f06635142837cf790480b37aa5fdc Mon Sep 17 00:00:00 2001 From: YuKun Liu Date: Sat, 2 Apr 2022 23:51:52 +0800 Subject: [PATCH 089/895] Update config.rs --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 3fc63637c..e664edbfc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,7 +65,7 @@ pub struct ApplicationConfig { pub default_platform: String, pub out_dir: Option, pub asset_dir: Option, - pub tools: Option> + pub tools: Option>, pub sub_package: Option, } From 280480de6bd7c9d95910be0932edb31b984827f3 Mon Sep 17 00:00:00 2001 From: Ben Birch Date: Thu, 7 Apr 2022 15:22:46 +1000 Subject: [PATCH 090/895] - set index on 404 to true (highly desired for SPA) - add support for web.base_path in dioxus.toml to allow multi level routes --- src/assets/index.html | 45 +++++++++++++++++++++++-------------------- src/builder.rs | 12 +++++++++--- src/config.rs | 4 +++- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/assets/index.html b/src/assets/index.html index bff411bee..f907aa281 100644 --- a/src/assets/index.html +++ b/src/assets/index.html @@ -1,23 +1,26 @@ - - {app_title} - - - - {style_include} - - -
- - - {script_include} - - + + {app_title} + + + + {style_include} + + + + +
+ + + {script_include} + + + \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 708e1ce69..bacfcd664 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -82,20 +82,21 @@ pub fn build(config: &CrateConfig) -> Result<()> { bindgen_builder .input_path(input_path) - .web(true).unwrap() + .web(true) + .unwrap() .debug(true) .demangle(true) .keep_debug(true) .remove_name_section(false) .remove_producers_section(false) .out_name(&dioxus_config.application.name) - .generate(&bindgen_outdir).unwrap(); + .generate(&bindgen_outdir) + .unwrap(); }); if bindgen_result.is_err() { log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate."); } - // this code will copy all public file to the output dir let copy_options = fs_extra::dir::CopyOptions { overwrite: true, @@ -278,6 +279,11 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { html = html.replace("{app_name}", &config.application.name); + html = match &config.web.app.base_path { + Some(path) => html.replace("{base_path}", path), + None => html.replace("{base_path}", "."), + }; + let title = config .web .app diff --git a/src/config.rs b/src/config.rs index fbf6f4b9d..9e8b47f7a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -39,11 +39,12 @@ impl Default for DioxusConfig { web: WebConfig { app: WebAppConfing { title: Some("dioxus | ⛺".into()), + base_path: None, }, watcher: WebWatcherConfing { watch_path: Some(vec![PathBuf::from("src")]), reload_html: Some(false), - index_on_404: Some(false), + index_on_404: Some(true), }, resource: WebResourceConfing { dev: WebDevResourceConfing { @@ -77,6 +78,7 @@ pub struct WebConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfing { pub title: Option, + pub base_path: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] From 714c6dd46ff383abfa749e6c3d9d82bbbfd6bdb5 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 17 Apr 2022 11:24:17 +0800 Subject: [PATCH 091/895] Upgrade `axum` version --- Cargo.toml | 2 +- src/builder.rs | 8 ++++---- src/cli/serve/mod.rs | 15 ++++----------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f5ded9be..21e2dad7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ chrono = "0.4.19" anyhow = "1.0.53" hyper = "0.14.17" -axum = { version = "0.4.5", features = ["ws", "headers"] } +axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } headers = "0.3.7" # tools download diff --git a/src/builder.rs b/src/builder.rs index aaaa0278a..09a410458 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -206,16 +206,16 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { file_name = name.clone(); config .target_dir - .join(release_type.to_string()) - .join(name.to_string()) + .join(release_type) + .join(name) } crate::ExecutableType::Example(name) => { file_name = name.clone(); config .target_dir - .join(release_type.to_string()) + .join(release_type) .join("examples") - .join(name.to_string()) + .join(name) } }; diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 21d29cd93..85bd92c74 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -1,9 +1,9 @@ +use super::*; use std::{ io::Write, path::PathBuf, process::{Command, Stdio}, }; -use super::*; /// Run the WASM project on dev-server #[derive(Clone, Debug, Parser)] @@ -47,16 +47,9 @@ impl Serve { if cfg!(windows) { file.set_extension("exe"); } - Command::new( - crate_config - .out_dir - .join(file) - .to_str() - .unwrap() - .to_string(), - ) - .stdout(Stdio::inherit()) - .output()?; + Command::new(crate_config.out_dir.join(file).to_str().unwrap()) + .stdout(Stdio::inherit()) + .output()?; } } return Ok(()); From 001410f1196f2ea6fe35084b5d489f48d104ca83 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 17 Apr 2022 11:25:53 +0800 Subject: [PATCH 092/895] Format code --- src/builder.rs | 7 ++----- src/cli/build/mod.rs | 1 - src/cli/config/mod.rs | 2 +- src/cli/mod.rs | 2 +- src/cli/tool/mod.rs | 6 ++---- src/config.rs | 2 +- 6 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 09a410458..f7f68e2bc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -132,7 +132,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { ); } } - + // this code will copy all public file to the output dir let copy_options = fs_extra::dir::CopyOptions { overwrite: true, @@ -204,10 +204,7 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { 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) + config.target_dir.join(release_type).join(name) } crate::ExecutableType::Example(name) => { file_name = name.clone(); diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 3b4d343af..4c043091f 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -12,7 +12,6 @@ impl Build { pub fn build(self) -> Result<()> { let mut crate_config = crate::CrateConfig::new()?; - // change the release state. crate_config.with_release(self.build.release); diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index fb1e046fb..5f9fa20d0 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -21,7 +21,7 @@ pub enum Config { /// Format print Dioxus config. FormatPrint {}, /// Create a custom html file. - CustomHtml {} + CustomHtml {}, } impl Config { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2c91c94dd..d639d28a7 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -4,8 +4,8 @@ pub mod clean; pub mod config; pub mod create; pub mod serve; -pub mod translate; pub mod tool; +pub mod translate; use crate::{ cfg::{ConfigOptsBuild, ConfigOptsServe}, diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index 51e41e384..d5c4581aa 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -11,9 +11,7 @@ pub enum Tool { /// Get default app install path. AppPath {}, /// Install a new tool. - Add { - name: String - } + Add { name: String }, } impl Tool { @@ -33,7 +31,7 @@ impl Tool { } Tool::Add { name } => { let tool_list = tools::tool_list(); - + if !tool_list.contains(&name.as_str()) { log::error!("Tool {name} not found."); return Ok(()); diff --git a/src/config.rs b/src/config.rs index 0cdd0bd8b..783c72ccd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use crate::error::Result; use serde::{Deserialize, Serialize}; -use std::{fs::File, io::Read, path::PathBuf, collections::HashMap}; +use std::{collections::HashMap, fs::File, io::Read, path::PathBuf}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DioxusConfig { From 569b294ab9fe98960f89c9eb4e75158f7db4b8cb Mon Sep 17 00:00:00 2001 From: Michael Mroz Date: Sun, 17 Apr 2022 01:13:48 -0700 Subject: [PATCH 093/895] Opt into standards mode --- src/assets/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/assets/index.html b/src/assets/index.html index f57acbd34..87d447816 100644 --- a/src/assets/index.html +++ b/src/assets/index.html @@ -1,3 +1,4 @@ + {app_title} From f203b5f99d7bed69f638073ac86fd911b14f2c19 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 24 Apr 2022 10:44:06 +0800 Subject: [PATCH 094/895] Move `docs` to cli repo --- .github/workflows/docs.yml | 32 ++++++++ docs/.gitignore | 1 + docs/book.toml | 6 ++ docs/src/SUMMARY.md | 11 +++ docs/src/cmd/README.md | 26 +++++++ docs/src/cmd/build.md | 47 ++++++++++++ docs/src/cmd/clean.md | 18 +++++ docs/src/cmd/serve.md | 49 +++++++++++++ docs/src/cmd/translate.md | 57 ++++++++++++++ docs/src/configure.md | 147 +++++++++++++++++++++++++++++++++++++ docs/src/creating.md | 38 ++++++++++ docs/src/installation.md | 24 ++++++ docs/src/introduction.md | 21 ++++++ 13 files changed, 477 insertions(+) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/.gitignore create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/cmd/README.md create mode 100644 docs/src/cmd/build.md create mode 100644 docs/src/cmd/clean.md create mode 100644 docs/src/cmd/serve.md create mode 100644 docs/src/cmd/translate.md create mode 100644 docs/src/configure.md create mode 100644 docs/src/creating.md create mode 100644 docs/src/installation.md create mode 100644 docs/src/introduction.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..2638b8a18 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,32 @@ +name: github pages + +on: + push: + paths: + - docs/** + - .github/workflows/docs.yml + branches: + - master + +jobs: + build-deploy: + runs-on: ubuntu-latest + environment: docs + steps: + - uses: actions/checkout@v2 + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v1 + with: + mdbook-version: "0.4.10" + + - name: Build + run: cd docs && md build -d ../build + + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@v4.2.3 + with: + branch: gh-pages # The branch the action should deploy to. + folder: build # The folder the action should deploy. + clean: false + token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..7585238ef --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 000000000..c5c216fe4 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["YuKun Liu"] +language = "en" +multilingual = false +src = "src" +title = "Dioxus Cli" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 000000000..ed7bcbfaf --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,11 @@ +# Summary + +- [Introduction](./introduction.md) +- [Installation](./installation.md) +- [Create a Project](./creating.md) +- [Configure Project](./configure.md) +- [Commands](./cmd/README.md) + - [Build](./cmd/build.md) + - [Serve](./cmd/serve.md) + - [Clean](./cmd/clean.md) + - [Translate](./cmd/translate.md) \ No newline at end of file diff --git a/docs/src/cmd/README.md b/docs/src/cmd/README.md new file mode 100644 index 000000000..c642b475f --- /dev/null +++ b/docs/src/cmd/README.md @@ -0,0 +1,26 @@ +# Commands + +In this chapter we will introduce all `dioxus-cli` commands. + +> you can also use `dioxus --help` to get cli help info. + +``` +dioxus +Build, bundle, & ship your Dioxus app + +USAGE: + dioxus [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v Enable verbose logging + +SUBCOMMANDS: + build Build the Rust WASM app and all of its assets + clean Clean output artifacts + config Dioxus config file controls + create Init a new project for Dioxus + help Print this message or the help of the given subcommand(s) + serve Build, watch & serve the Rust WASM app and all of its assets + translate Translate some source file into Dioxus code +``` \ No newline at end of file diff --git a/docs/src/cmd/build.md b/docs/src/cmd/build.md new file mode 100644 index 000000000..e81973f2d --- /dev/null +++ b/docs/src/cmd/build.md @@ -0,0 +1,47 @@ +# Build + +The `dioxus build` command can help you `pack & build` a dioxus project. + +``` +dioxus-build +Build the Rust WASM app and all of its assets + +USAGE: + dioxus build [OPTIONS] + +OPTIONS: + --example [default: ""] + --platform [default: "default_platform"] + --release [default: false] +``` + +You can use this command to build project to `out_dir` : + +``` +dioxus build --release +``` + +## Target platform + +Use option `platform` choose build target platform: + +``` +# for desktop project +dioxus build --platform desktop +``` + +`platform` only supports `desktop` & `web`. + +``` +# for web project +dioxus build --platform web +``` + +## Build Example + +You can use `--example {name}` to build a example code. + +``` +# build `example/test` code +dioxus build --exmaple test +``` \ No newline at end of file diff --git a/docs/src/cmd/clean.md b/docs/src/cmd/clean.md new file mode 100644 index 000000000..2f889c1a8 --- /dev/null +++ b/docs/src/cmd/clean.md @@ -0,0 +1,18 @@ +# Clean + +`dioxus clean` will call `target clean` and remove `out_dir` directory. + +``` +dioxus-clean +Clean output artifacts + +USAGE: + dioxus clean +``` + +you can use this command to clean all build cache and the `out_dir` content. + +``` +dioxus clean +``` + diff --git a/docs/src/cmd/serve.md b/docs/src/cmd/serve.md new file mode 100644 index 000000000..e5c10a902 --- /dev/null +++ b/docs/src/cmd/serve.md @@ -0,0 +1,49 @@ +# Serve + +The `dioxus serve` can start a dev server (include hot-reload tool) to run the project. + +``` +dioxus-serve +Build, watch & serve the Rust WASM app and all of its assets + +USAGE: + dioxus serve [OPTIONS] + +OPTIONS: + --example [default: ""] + --platform [default: "default_platform"] + --release [default: false] +``` + +You can use this command to build project and start a `dev server` : + +``` +dioxus serve +``` + +## Target platform + +Use option `platform` choose build target platform: + +``` +# for desktop project +dioxus serve --platform desktop +``` + +`platform` only supports `desktop` & `web`. + +`dev-server` only for `web` project. + +``` +# for web project +dioxus serve --platform web +``` + +## Serve Example + +You can use `--example {name}` to start a example code. + +``` +# build `example/test` code +dioxus serve --exmaple test +``` \ No newline at end of file diff --git a/docs/src/cmd/translate.md b/docs/src/cmd/translate.md new file mode 100644 index 000000000..415a88fba --- /dev/null +++ b/docs/src/cmd/translate.md @@ -0,0 +1,57 @@ +# Translate + +`dioxus translate` can translate some source file into Dioxus code. + +``` +dioxus-translate +Translate some source file into Dioxus code + +USAGE: + dioxus translate [OPTIONS] [OUTPUT] + +ARGS: + Output file, stdout if not present + +OPTIONS: + -c, --component Activate debug mode + -f, --file Input file +``` + +## Translate HTML to stdout + +``` +dioxus transtale --file ./index.html +``` + +## Output in a file + +``` +dioxus translate --component --file ./index.html component.rsx +``` + +set `component` flag will wrap `dioxus rsx` code in a component function. + +## Example + +```html +
+

Hello World

+ Link +
+``` + +Translate HTML to Dioxus component code. + +```rust +fn component(cx: Scope) -> Element { + cx.render(rsx! { + div { + h1 { "Hello World" }, + a { + href: "https://dioxuslabs.com/", + "Link" + } + } + }) +} +``` \ No newline at end of file diff --git a/docs/src/configure.md b/docs/src/configure.md new file mode 100644 index 000000000..f274ce70d --- /dev/null +++ b/docs/src/configure.md @@ -0,0 +1,147 @@ +# Configure Project + +This chapter will introduce `Dioxus.toml` and anatomy the config file. + +## Structure + +We use `toml` to define some info for `dioxus` project. + +### Application + +1. ***name*** - project name & title +2. ***default_platform*** - which platform target for this project. + ``` + # current support: web, desktop + # default: web + default_platform = "web" + ``` + change this to `desktop`, the `dioxus build & serve` will default build desktop app. +3. ***out_dir*** - which directory to put the output file; use `dioxus build & service`, the output will put at this directory, and the `assets` will be also copy to here. + ``` + out_dir = "dist" + ``` +4. ***asset_dir*** - which direcotry to put your `static, assets` file, cli will automatic copy all file to `out_dir`, so you can put some resource file in there, like `CSS, JS, Image` file. + ``` + asset_dir = "public" + ``` + +### Web.App + +Web platform application config: + +1. ***title*** - this value will display on the web page title. like `` tag. + ``` + # HTML title tag content + title = "dioxus app | ⛺" + ``` + +### Web.Watcher + +Web platform `dev-server` watcher config: + +1. ***reload_html*** - a boolean value; when watcher trigger, regenerate `index.html` file. + ``` + # when watcher trigger, regenerate the `index.html` + reload_html = true + ``` +2. ***watch_path*** - which files & directories will be watcher monitoring. + ``` + watch_path = ["src", "public"] + ``` + +### Web.Resource + +Include some `CSS Javascript` resources into html file. + +1. ***style*** - include some style(CSS) file into html. + ``` + style = [ + # include from public_dir. + "./assets/style.css", + # or some asset from online cdn. + "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css" + ] + ``` +2. ***script*** - include some script(JS) file into html. + ``` + style = [ + # include from public_dir. + "./assets/index.js", + # or some asset from online cdn. + "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js" + ] + ``` + +### Web.Resource.Dev + +Only include resources at `Dev` mode. + +1. ***style*** - include some style(CSS) file into html. + ``` + style = [ + # include from public_dir. + "./assets/style.css", + # or some asset from online cdn. + "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css" + ] + ``` +2. ***script*** - include some script(JS) file into html. + ``` + style = [ + # include from public_dir. + "./assets/index.js", + # or some asset from online cdn. + "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js" + ] + ``` + +## Config example + +```toml +[application] + +# App (Project) Name +name = "{{project-name}}" + +# Dioxus App Default Platform +# desktop, web, mobile, ssr +default_platform = "web" + +# `build` & `serve` dist path +out_dir = "dist" + +# resource (public) file folder +asset_dir = "public" + +[web.app] + +# HTML title tag content +title = "dioxus | ⛺" + +[web.watcher] + +# when watcher trigger, regenerate the `index.html` +reload_html = true + +# which files or dirs will be watcher monitoring +watch_path = ["src", "public"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# serve: [dev-server] only + +# CSS style file +style = [] + +# Javascript code file +script = [] +``` \ No newline at end of file diff --git a/docs/src/creating.md b/docs/src/creating.md new file mode 100644 index 000000000..fa725a4f7 --- /dev/null +++ b/docs/src/creating.md @@ -0,0 +1,38 @@ +# Create a Project + +Once you have the Dioxus CLI tool installed, you can use it to create dioxus project. + +## Initializing a default project + +The `dioxus create` command will create a new directory containing a project template. +``` +dioxus create hello-dioxus +``` + +It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template) + +> This default template is use for `web` platform application. + +then you can change the current directory in to the project: + +``` +cd hello-dioxus +``` + +> Make sure `wasm32 target` is installed before running the Web project. + +now we can create a `dev server` to display the project: + +``` +dioxus serve +``` + +by default, the dioxus dev server will running at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/) + +## Initalizing from other repository + +you can assign which repository you want to create: + +``` +dioxus init hello-dioxus --template=gh:dioxuslabs/dioxus-template +``` \ No newline at end of file diff --git a/docs/src/installation.md b/docs/src/installation.md new file mode 100644 index 000000000..7151de1ff --- /dev/null +++ b/docs/src/installation.md @@ -0,0 +1,24 @@ +# Installation + +There are multiple ways to install the Dioxus CLI tool. Choose any one of the methods below that best suit your needs. + +## Install from latest master version + +We suggest you use `github master` version to install it now. + +We have not yet released the latest version to `crates.io` + +``` +cargo install --git https://github.com/Dioxuslabs/cli +``` + +This will automatically download `Dioxus-CLI` source from github master branch, +and install it in Cargo's global binary directory (`~/.cargo/bin/` by default). + +## Install from `crates.io` version + +``` +cargo install dioxus-cli +``` + +Make sure to add the Cargo bin directory to your `PATH`. \ No newline at end of file diff --git a/docs/src/introduction.md b/docs/src/introduction.md new file mode 100644 index 000000000..2f857a2a5 --- /dev/null +++ b/docs/src/introduction.md @@ -0,0 +1,21 @@ +# Introduction + +📦✨ **Dioxus-Cli** is a tool to help get dioxus projects off the ground. + +![dioxus-logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png) + +It includes `dev server`, `hot reload` and some `quick command` to help you use dioxus. + +## Features + +- [x] `html` to `rsx` conversion tool +- [x] hot reload for `web` platform +- [x] create dioxus project from `git` repo +- [x] build & pack dioxus project +- [ ] autoformat dioxus `rsx` code + +## Contributors + +Contributors to this guide: + +- [mrxiaozhuox](https://github.com/mrxiaozhuox) \ No newline at end of file From 79df0d0f742f98c7d54a5463e62a19a3ef0b36c8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 24 Apr 2022 10:47:04 +0800 Subject: [PATCH 095/895] Fixed workflows --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2638b8a18..c6ae8be13 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -21,7 +21,7 @@ jobs: mdbook-version: "0.4.10" - name: Build - run: cd docs && md build -d ../build + run: cd docs && mdbook build -d ../build - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@v4.2.3 From 1f1de4d82219125df7ff4654b76c7ef3d7d3ba1b Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 24 Apr 2022 11:03:46 +0800 Subject: [PATCH 096/895] Fixed docs.yml --- .github/workflows/docs.yml | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c6ae8be13..5643e6194 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,31 +2,29 @@ name: github pages on: push: - paths: - - docs/** - - .github/workflows/docs.yml branches: - - master + - main + pull_request: jobs: - build-deploy: - runs-on: ubuntu-latest - environment: docs + deploy: + runs-on: ubuntu-20.04 + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} steps: - uses: actions/checkout@v2 - name: Setup mdBook uses: peaceiris/actions-mdbook@v1 with: - mdbook-version: "0.4.10" + mdbook-version: '0.4.10' + # mdbook-version: 'latest' - - name: Build - run: cd docs && mdbook build -d ../build + - run: cd docs && mdbook build - - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.2.3 + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.ref == 'refs/heads/main' }} with: - branch: gh-pages # The branch the action should deploy to. - folder: build # The folder the action should deploy. - clean: false - token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/book \ No newline at end of file From 5f7daedc5d0a9515fce711804e1eaf94204cf6df Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 24 Apr 2022 11:22:02 +0800 Subject: [PATCH 097/895] Update docs.yml --- .github/workflows/docs.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 5643e6194..2ed974a47 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,9 +22,12 @@ jobs: - run: cd docs && mdbook build - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.ref == 'refs/heads/main' }} + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@v4.2.3 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs/book \ No newline at end of file + branch: gh-pages # The branch the action should deploy to. + folder: docs/book # The folder the action should deploy. + target-folder: docs/nightly/cli + repository-name: dioxuslabs/docsite + clean: false + token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now \ No newline at end of file From 04535749e9668b04a37d192fedc258ba6d9168ef Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sat, 23 Apr 2022 23:28:53 -0400 Subject: [PATCH 098/895] chore: clean up some latent items --- TODO.md | 11 ----------- out.rsx | 23 ----------------------- test.html | 5 ----- 3 files changed, 39 deletions(-) delete mode 100644 TODO.md delete mode 100644 out.rsx delete mode 100644 test.html diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 6fd51d591..000000000 --- a/TODO.md +++ /dev/null @@ -1,11 +0,0 @@ - -asd -- [ ] use a TUI for the dev server aspect of things -- [ ] allow any index.html -- [ ] use wasmopt for production builds -- [ ] pass arguments through to `cargo` -- [ ] figure out a bundling strategy -- [ ] an external configuration - - -should we just use trunk? diff --git a/out.rsx b/out.rsx deleted file mode 100644 index b30b76f9e..000000000 --- a/out.rsx +++ /dev/null @@ -1,23 +0,0 @@ - -use dioxus::prelude::*; -fn component(cx: Scope) -> Element { - cx.render(rsx!( - div { - h1 { - "hello" - } - } - )) -} - -use dioxus::prelude::*; -fn component(cx: Scope) -> Element { - cx.render(rsx!( - div { - h1 { - "hello" - } - } - )) -} - diff --git a/test.html b/test.html deleted file mode 100644 index 33ca3dd1f..000000000 --- a/test.html +++ /dev/null @@ -1,5 +0,0 @@ -
-

- hello -

-
From 3269b2b5aaaa95c55599bc311cc46ade38ca4630 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sat, 23 Apr 2022 23:55:18 -0400 Subject: [PATCH 099/895] feat: add more options to translation --- extension/package.json | 4 +-- extension/src/extension.ts | 5 ++- src/cli/translate/mod.rs | 22 +++++++++--- tests/test.html | 72 +++++++++++++++++++++++--------------- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/extension/package.json b/extension/package.json index 0a3d50b67..c492f97e2 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { "name": "dioxusstudio", - "displayName": "dioxusStudio", - "description": "Toolkit for IDE support in Dioxus apps", + "displayName": "Dioxus", + "description": "Useful tools for working with Dioxus", "version": "0.0.1", "publisher": "jkelleyrtp", "private": true, diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 5a41c7f5f..4322c48e1 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { spawn } from "child_process"; export function activate(context: vscode.ExtensionContext) { + function registerCommand(cmd: string) { function convert(cmd: string) { const editor = vscode.window.activeTextEditor;// Get the active text editor @@ -10,7 +11,7 @@ export function activate(context: vscode.ExtensionContext) { if (html.length > 0) { let params = ["translate"]; if (cmd.includes("Component")) params.push("--component"); - params.push("--source"); + params.push("--raw"); params.push(html); const child_proc = spawn("dioxus", params); let result = ''; @@ -23,6 +24,8 @@ export function activate(context: vscode.ExtensionContext) { } } } + + const handle = vscode.commands.registerCommand(cmd, () => convert(cmd)); context.subscriptions.push(handle); } diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index e239ce318..3440ee6b1 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -13,6 +13,10 @@ pub struct Translate { #[clap(short, long)] pub file: Option, + /// Input file + #[clap(short, long)] + pub raw: Option, + /// Output file, stdout if not present #[clap(parse(from_os_str))] pub output: Option, @@ -24,14 +28,20 @@ impl Translate { component, output, file, + raw, } = self; - let contents = match file { - Some(input) => std::fs::read_to_string(&input).unwrap_or_else(|e| { + let contents = match (file, raw) { + (Some(input), None) => std::fs::read_to_string(&input).unwrap_or_else(|e| { log::error!("Cloud not read input file: {}.", e); exit(0); }), - None => { + (None, Some(raw)) => raw, + (Some(_), Some(_)) => { + log::error!("Only one of --file or --raw can be specified."); + exit(0); + } + (None, None) => { if atty::is(atty::Stream::Stdin) { log::error!("No input file, source, or stdin to translate from."); exit(0); @@ -67,7 +77,11 @@ impl Translate { } /// render without handling svgs or anything -fn simple_render_child(f: &mut impl std::fmt::Write, child: &Node, il: u32) -> std::fmt::Result { +pub fn simple_render_child( + f: &mut impl std::fmt::Write, + child: &Node, + il: u32, +) -> std::fmt::Result { write_tabs(f, il)?; match child { Node::Text(t) => writeln!(f, "\"{}\"", t)?, diff --git a/tests/test.html b/tests/test.html index 4936ae36a..05ccd7b18 100644 --- a/tests/test.html +++ b/tests/test.html @@ -1,32 +1,48 @@
-
-
-
-
- content -
-

Buy YouTube Videos

-

- Williamsburg occupy sustainable snackwave gochujang. Pinterest cornhole brunch, slow-carb neutra - irony. -

- -
-
-
- content -
-

The Catalyzer

-

- Williamsburg occupy sustainable snackwave gochujang. Pinterest - cornhole brunch, slow-carb neutra irony. -

- -
+
+
+
+
+ content
+

+ Buy YouTube Videos +

+

+ Williamsburg occupy sustainable snackwave gochujang. Pinterest + cornhole brunch, slow-carb neutra irony. +

+ +
+
+
+ content +
+

+ The Catalyzer +

+

+ Williamsburg occupy sustainable snackwave gochujang. Pinterest + cornhole brunch, slow-carb neutra irony. +

+ +
+
From 84f0245f6c5fe18412b799e9019327fb73788083 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 24 Apr 2022 03:24:41 -0400 Subject: [PATCH 100/895] feat: basic autofmt --- Cargo.toml | 3 ++ extension/DEV.md | 10 +++++ extension/README.md | 10 ----- extension/package.json | 14 ++++-- extension/src/extension.ts | 86 ++++++++++++++++++++++++++----------- extension/static/icon.png | Bin 0 -> 20768 bytes src/cli/autoformat/mod.rs | 25 +++++++++++ src/cli/mod.rs | 11 +++++ src/main.rs | 6 +++ 9 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 extension/DEV.md create mode 100644 extension/static/icon.png create mode 100644 src/cli/autoformat/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 21e2dad7e..b8f0e271b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,9 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" +dioxus-rsx = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } +dioxus-autofmt = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } + [[bin]] path = "src/main.rs" name = "dioxus" diff --git a/extension/DEV.md b/extension/DEV.md new file mode 100644 index 000000000..54d0c396a --- /dev/null +++ b/extension/DEV.md @@ -0,0 +1,10 @@ + +## packaging + +``` +$ cd myExtension +$ vsce package +# myExtension.vsix generated +$ vsce publish +# .myExtension published to VS Code Marketplace +``` diff --git a/extension/README.md b/extension/README.md index bf9459fe9..fe67f1587 100644 --- a/extension/README.md +++ b/extension/README.md @@ -12,13 +12,3 @@ Converts a selection of html to valid rsx. ### Convert HTML to Dioxus Component Converts a selection of html to a valid Dioxus component with all SVGs factored out into their own module. - -## packaging - -``` -$ cd myExtension -$ vsce package -# myExtension.vsix generated -$ vsce publish -# .myExtension published to VS Code Marketplace -``` diff --git a/extension/package.json b/extension/package.json index c492f97e2..ca73c0ea8 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,14 +1,15 @@ { - "name": "dioxusstudio", + "name": "dioxus", "displayName": "Dioxus", "description": "Useful tools for working with Dioxus", "version": "0.0.1", - "publisher": "jkelleyrtp", + "publisher": "DioxusLabs", "private": true, "license": "MIT", + "icon": "static/icon.png", "repository": { "type": "git", - "url": "https://github.com/Microsoft/vscode-extension-samples" + "url": "https://github.com/DioxusLabs/cli" }, "engines": { "vscode": "^1.32.0" @@ -18,7 +19,8 @@ ], "activationEvents": [ "onCommand:extension.htmlToDioxusRsx", - "onCommand:extension.htmlToDioxusComponent" + "onCommand:extension.htmlToDioxusComponent", + "onCommand:extension.formatRsx" ], "main": "./out/extension", "contributes": { @@ -30,6 +32,10 @@ { "command": "extension.htmlToDioxusComponent", "title": "Dioxus: Convert HTML to Component" + }, + { + "command": "extension.formatRsx", + "title": "Dioxus: Format RSX" } ] }, diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 4322c48e1..fd8e2906b 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -3,33 +3,71 @@ import { spawn } from "child_process"; export function activate(context: vscode.ExtensionContext) { - function registerCommand(cmd: string) { - function convert(cmd: string) { - const editor = vscode.window.activeTextEditor;// Get the active text editor - if (editor) { - const html = editor.document.getText(editor.selection); - if (html.length > 0) { - let params = ["translate"]; - if (cmd.includes("Component")) params.push("--component"); - params.push("--raw"); - params.push(html); - const child_proc = spawn("dioxus", params); - let result = ''; - child_proc.stdout?.on('data', data => result += data); - child_proc.on('close', () => { - if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); - }); - } else { - vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!"); - } - } + + function translate(component: boolean) { + const editor = vscode.window.activeTextEditor;// Get the active text editor + if (!editor) return; + + const html = editor.document.getText(editor.selection); + if (html.length == 0) { + vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!"); + return; } + let params = ["translate"]; + if (component) params.push("--component"); + params.push("--raw"); + params.push(html); - const handle = vscode.commands.registerCommand(cmd, () => convert(cmd)); - context.subscriptions.push(handle); + const child_proc = spawn("dioxus", params); + + let result = ''; + child_proc.stdout?.on('data', data => result += data); + + child_proc.on('close', () => { + if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); } - registerCommand('extension.htmlToDioxusRsx'); - registerCommand('extension.htmlToDioxusComponent'); + function autoformat() { + const editor = vscode.window.activeTextEditor;// Get the active text editor + if (!editor) return; + + const unformatted = editor.document.getText(editor.selection); + if (unformatted.length == 0) { + vscode.window.showWarningMessage("Please select rsx invoking this command!"); + return; + } + + const params = ["fmt", "--raw", unformatted]; + + const child_proc = spawn("dioxus", params); + + let result = ''; + child_proc.stdout?.on('data', data => result += data); + + child_proc.on('close', () => { + if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); + } + + + + + const handles = + [ + vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)), + vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)), + vscode.commands.registerCommand('extension.formatRsx', () => autoformat()) + ]; + + context.subscriptions.push(...handles); } diff --git a/extension/static/icon.png b/extension/static/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..42c355c2647b0b68cf18c12d292db134ac8750d2 GIT binary patch literal 20768 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 IM6N<$f;9DK`~Uy| literal 0 HcmV?d00001 diff --git a/src/cli/autoformat/mod.rs b/src/cli/autoformat/mod.rs new file mode 100644 index 000000000..26ab86345 --- /dev/null +++ b/src/cli/autoformat/mod.rs @@ -0,0 +1,25 @@ +use super::*; + +/// Build the Rust WASM app and all of its assets. +#[derive(Clone, Debug, Parser)] +pub struct Autoformat { + /// Input file + #[clap(short, long)] + pub raw: Option, +} + +impl Autoformat { + pub fn autoformat(self) -> Result<()> { + if let Some(raw) = self.raw { + if let Some(inner) = dioxus_autofmt::fmt_block(&raw) { + println!("{}", inner); + } else { + // exit process with error + eprintln!("error formatting codeblock"); + exit(1); + } + } + + Ok(()) + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d639d28a7..92e05eaa9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,3 +1,4 @@ +pub mod autoformat; pub mod build; pub mod cfg; pub mod clean; @@ -45,17 +46,27 @@ pub struct Cli { pub enum Commands { /// Build the Rust WASM app and all of its assets. Build(build::Build), + /// Translate some source file into Dioxus code. Translate(translate::Translate), + /// Build, watch & serve the Rust WASM app and all of its assets. Serve(serve::Serve), + /// Init a new project for Dioxus. Create(create::Create), + /// Clean output artifacts. Clean(clean::Clean), + + /// Format some rsx + #[clap(name = "fmt")] + Autoformat(autoformat::Autoformat), + /// Dioxus config file controls. #[clap(subcommand)] Config(config::Config), + /// Install & Manage tools for Dioxus-cli. #[clap(subcommand)] Tool(tool::Tool), diff --git a/src/main.rs b/src/main.rs index 099ff74c0..72558741e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,6 +48,12 @@ async fn main() -> Result<()> { log::error!("tool error: {}", e); } } + + Commands::Autoformat(opts) => { + if let Err(e) = opts.autoformat() { + log::error!("format error: {}", e); + } + } } Ok(()) From 201dcc144d363571865ace40d85336b3c792d474 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 26 Apr 2022 18:45:27 -0400 Subject: [PATCH 101/895] feat: fix bug with applying multiple edits in sequence --- Cargo.toml | 6 ++- extension/package.json | 7 +++- extension/src/extension.ts | 85 ++++++++++++++++++++++++++++++++------ src/cli/autoformat/mod.rs | 38 ++++++++++++++++- 4 files changed, 120 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b8f0e271b..9f85a89c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,8 +46,10 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" -dioxus-rsx = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } -dioxus-autofmt = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } +dioxus-rsx = { path = "../../dioxus/packages/rsx" } +dioxus-autofmt = { path = "../../dioxus/packages/autofmt" } +# dioxus-rsx = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } +# dioxus-autofmt = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } [[bin]] path = "src/main.rs" diff --git a/extension/package.json b/extension/package.json index ca73c0ea8..f884637c8 100644 --- a/extension/package.json +++ b/extension/package.json @@ -20,7 +20,8 @@ "activationEvents": [ "onCommand:extension.htmlToDioxusRsx", "onCommand:extension.htmlToDioxusComponent", - "onCommand:extension.formatRsx" + "onCommand:extension.formatRsx", + "onCommand:extension.formatRsxDocument" ], "main": "./out/extension", "contributes": { @@ -36,6 +37,10 @@ { "command": "extension.formatRsx", "title": "Dioxus: Format RSX" + }, + { + "command": "extension.formatRsxDocument", + "title": "Dioxus: Format RSX Document" } ] }, diff --git a/extension/src/extension.ts b/extension/src/extension.ts index fd8e2906b..46ce2aa89 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -33,7 +33,7 @@ export function activate(context: vscode.ExtensionContext) { }); } - function autoformat() { + function autoformat_selection() { const editor = vscode.window.activeTextEditor;// Get the active text editor if (!editor) return; @@ -43,11 +43,10 @@ export function activate(context: vscode.ExtensionContext) { return; } - const params = ["fmt", "--raw", unformatted]; - - const child_proc = spawn("dioxus", params); - + let args = ["fmt", "--raw", unformatted.toString()]; + const child_proc = spawn("dioxus", args); let result = ''; + child_proc.stdout?.on('data', data => result += data); child_proc.on('close', () => { @@ -60,14 +59,76 @@ export function activate(context: vscode.ExtensionContext) { } + function autoformat_document(document: vscode.TextDocument) { + // check the settings to make sure format on save is configured + // const formatOnSave: string | undefined = vscode.workspace.getConfiguration('rust').get('formatOnSave'); + if (document.languageId === "rust" && document.uri.scheme === "file") { + const editor = vscode.window.activeTextEditor;// Get the active text editor + if (editor) { + const text = editor.document.getText(); - const handles = - [ - vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)), - vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)), - vscode.commands.registerCommand('extension.formatRsx', () => autoformat()) - ]; + console.error(text); - context.subscriptions.push(...handles); + const child_proc = spawn("dioxus", ["fmt", "-f", text]); + + let result = ''; + + child_proc.stdout?.on('data', data => result += data); + + type RsxEdit = { + formatted: string, + start: number, + end: number + } + + child_proc.on('close', () => { + // if (result.length > 0) { + // editor.edit(editBuilder => editBuilder.insert(new vscode.Position(0, 0), result)); + // } else { + // console.error("No result"); + // } + if (result.length > 0) { + let decoded: RsxEdit[] = JSON.parse(result); + + console.log("Decoded edits: ", decoded); + + editor.edit(editBuilder => { + + for (let edit of decoded) { + console.log("Handling Edit: ", edit); + + let start = document.positionAt(edit.start - 1); + let end = document.positionAt(edit.end + 1); + const range = new vscode.Range(start, end); + + editBuilder.replace(range, `{ ${edit.formatted} }`); + // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { + // }); + // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { + // console.log("Edit applied: ", could_be_applied); + // }); + } + }) + } + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); + } + } + } + + context.subscriptions.push( + vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)), + vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)), + vscode.commands.registerCommand('extension.formatRsx', () => autoformat_selection()), + vscode.commands.registerCommand('extension.formatRsxDocument', () => { + const editor = vscode.window.activeTextEditor;// Get the active text editor + if (!editor) return; + autoformat_document(editor.document); + }), + vscode.workspace.onDidSaveTextDocument(autoformat_document) + ); } diff --git a/src/cli/autoformat/mod.rs b/src/cli/autoformat/mod.rs index 26ab86345..3008411db 100644 --- a/src/cli/autoformat/mod.rs +++ b/src/cli/autoformat/mod.rs @@ -3,9 +3,13 @@ use super::*; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Parser)] pub struct Autoformat { - /// Input file + /// Input rsx (selection) #[clap(short, long)] pub raw: Option, + + /// Input file + #[clap(short, long)] + pub file: Option, } impl Autoformat { @@ -20,6 +24,38 @@ impl Autoformat { } } + if let Some(file) = self.file { + let edits = dioxus_autofmt::get_format_blocks(&file); + let as_json = serde_json::to_string(&edits).unwrap(); + println!("{}", as_json); + } + Ok(()) } } + +#[test] +fn spawn_properly() { + let out = Command::new("dioxus") + .args([ + "fmt", + "-f", + r#" +// + +rsx! { + + div {} +} + +// +// +// + + "#, + ]) + .output() + .expect("failed to execute process"); + + dbg!(out); +} From 4a54934c8ef34d98861223bcf5be244fa3922027 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 28 Apr 2022 23:59:20 -0400 Subject: [PATCH 102/895] fix: extension should respect blocks --- extension/src/extension.ts | 49 +++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 46ce2aa89..44d5b8f16 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -64,9 +64,10 @@ export function activate(context: vscode.ExtensionContext) { // const formatOnSave: string | undefined = vscode.workspace.getConfiguration('rust').get('formatOnSave'); if (document.languageId === "rust" && document.uri.scheme === "file") { - const editor = vscode.window.activeTextEditor;// Get the active text editor - if (editor) { - const text = editor.document.getText(); + const active_editor = vscode.window.activeTextEditor;// Get the active text editor + + if (active_editor?.document.fileName === document.fileName) { + const text = document.getText(); console.error(text); @@ -83,33 +84,37 @@ export function activate(context: vscode.ExtensionContext) { } child_proc.on('close', () => { - // if (result.length > 0) { - // editor.edit(editBuilder => editBuilder.insert(new vscode.Position(0, 0), result)); - // } else { - // console.error("No result"); - // } + if (result.length > 0) { let decoded: RsxEdit[] = JSON.parse(result); console.log("Decoded edits: ", decoded); - editor.edit(editBuilder => { + // Get the active text editor + const cur_editor = vscode.window.activeTextEditor; - for (let edit of decoded) { - console.log("Handling Edit: ", edit); - let start = document.positionAt(edit.start - 1); - let end = document.positionAt(edit.end + 1); - const range = new vscode.Range(start, end); + // even if we build an empty edit stream, it tries to save the editor + // this makes sure the editor is actually saved + if (decoded.length > 0 && cur_editor == active_editor) { + active_editor.edit(editBuilder => { - editBuilder.replace(range, `{ ${edit.formatted} }`); - // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { - // }); - // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { - // console.log("Edit applied: ", could_be_applied); - // }); - } - }) + for (let edit of decoded) { + console.log("Handling Edit: ", edit); + + let start = document.positionAt(edit.start - 1); + let end = document.positionAt(edit.end + 1); + const range = new vscode.Range(start, end); + + editBuilder.replace(range, `{ ${edit.formatted} }`); + // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { + // }); + // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { + // console.log("Edit applied: ", could_be_applied); + // }); + } + }) + } } }); From 2c9f5f1957941dd7875f0b01742809f9ec0823f1 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Fri, 29 Apr 2022 12:59:15 +0800 Subject: [PATCH 103/895] Fixed `dioxus.toml` --- src/assets/dioxus.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index ab85abe86..b43d0d6df 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -42,4 +42,4 @@ script = [] # use binaryen.wasm-opt for output Wasm file # binaryen just will trigger in `web` platform -binaryen = { wasm_opt = [".PROJECT_OUT"] } \ No newline at end of file +binaryen = { wasm_opt = true } \ No newline at end of file From 5d013ecf824b1e62b8741e7e4565af8bf3262f97 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 7 May 2022 11:54:00 +0800 Subject: [PATCH 104/895] Try to add `Sass` support --- src/assets/dioxus.toml | 5 ++++- src/tools.rs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index b43d0d6df..0c57542b8 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -42,4 +42,7 @@ script = [] # use binaryen.wasm-opt for output Wasm file # binaryen just will trigger in `web` platform -binaryen = { wasm_opt = true } \ No newline at end of file +binaryen = { wasm_opt = true } + +# use sass auto will auto check sass file and build it. +sass = { auto = true } \ No newline at end of file diff --git a/src/tools.rs b/src/tools.rs index 937063be0..db4d82268 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -13,10 +13,11 @@ use tokio::io::AsyncWriteExt; #[derive(Debug, PartialEq, Eq)] pub enum Tool { Binaryen, + Sass, } pub fn tool_list() -> Vec<&'static str> { - vec!["binaryen"] + vec!["binaryen", "sass"] } pub fn app_path() -> PathBuf { @@ -60,6 +61,7 @@ impl Tool { pub fn name(&self) -> &str { match self { Self::Binaryen => "binaryen", + Self::Sass => "sass", } } @@ -67,6 +69,7 @@ impl Tool { pub fn bin_path(&self) -> &str { match self { Self::Binaryen => "bin", + Self::Sass => ".", } } @@ -84,6 +87,17 @@ impl Tool { panic!("unsupported platformm"); } } + Self::Sass => { + if cfg!(target_os = "windows") { + "windows" + } else if cfg!(target_os = "macos") { + "macos" + } else if cfg!(target_os = "linux") { + "linux" + } else { + panic!("unsupported platformm"); + } + } } } @@ -96,6 +110,12 @@ impl Tool { target = self.target_platform() ) } + Self::Sass => { + format!( + "https://github.com/sass/dart-sass/releases/download/1.51.0/dart-sass-1.51.0-{target}-x64.tar.gz", + target = self.target_platform() + ) + } } } @@ -103,6 +123,13 @@ impl Tool { pub fn extension(&self) -> &str { match self { Self::Binaryen => "tar.gz", + Self::Sass => { + if cfg!(target_os = "windows") { + "zip" + } else { + "tar.ge" + } + }, } } @@ -169,6 +196,9 @@ impl Tool { command.to_string() } } + Tool::Sass => { + command.to_string() + } }; if !bin_path.join(&command_file).is_file() { From c48345b86e556c0535d4ead6134921c68d4c121c Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 7 May 2022 16:25:23 +0800 Subject: [PATCH 105/895] Add `zip` support --- Cargo.toml | 2 ++ src/tools.rs | 46 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 21e2dad7e..d2bda881f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,13 @@ hyper = "0.14.17" axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } headers = "0.3.7" + # tools download dirs = "4.0.0" reqwest = { version = "0.11", features = ["rustls-tls", "stream", "trust-dns"] } flate2 = "1.0.22" tar = "0.4.38" +zip = "0.6.2" tower = "0.4.12" [[bin]] diff --git a/src/tools.rs b/src/tools.rs index db4d82268..b37d10cd2 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -1,6 +1,6 @@ use std::{ fs::{create_dir_all, File}, - path::PathBuf, + path::{Path, PathBuf}, process::Command, }; @@ -112,8 +112,9 @@ impl Tool { } Self::Sass => { format!( - "https://github.com/sass/dart-sass/releases/download/1.51.0/dart-sass-1.51.0-{target}-x64.tar.gz", - target = self.target_platform() + "https://github.com/sass/dart-sass/releases/download/1.51.0/dart-sass-1.51.0-{target}-x64.{extension}", + target = self.target_platform(), + extension = self.extension() ) } } @@ -129,7 +130,7 @@ impl Tool { } else { "tar.ge" } - }, + } } } @@ -169,6 +170,8 @@ impl Tool { let dir_name = if self == &Tool::Binaryen { "binaryen-version_105" + } else if self == &Tool::Sass { + "sass-version-1_51" } else { "" }; @@ -180,6 +183,8 @@ impl Tool { archive.unpack(&tool_path)?; // println!("{:?} -> {:?}", tool_path.join(dir_name), tool_path.join(self.name())); std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?; + } else if self.extension() == "zip" { + // decompress the `zip` file } Ok(()) @@ -196,9 +201,7 @@ impl Tool { command.to_string() } } - Tool::Sass => { - command.to_string() - } + Tool::Sass => command.to_string(), }; if !bin_path.join(&command_file).is_file() { @@ -215,3 +218,32 @@ impl Tool { Ok(output.stdout) } } + +fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> { + let zip_file = std::fs::File::open(&file)?; + let mut zip = zip::ZipArchive::new(zip_file)?; + + if !target.exists() { + let _ = std::fs::create_dir_all(target)?; + } + + for i in 0..zip.len() { + let mut file = zip.by_index(i)?; + if file.is_dir() { + // dir + let target = target.join(Path::new(&file.name().replace('\\', ""))); + let _ = std::fs::create_dir_all(target)?; + } else { + // file + let file_path = target.join(Path::new(file.name())); + let mut target_file = if !file_path.exists() { + std::fs::File::create(file_path)? + } else { + std::fs::File::open(file_path)? + }; + let _num = std::io::copy(&mut file, &mut target_file)?; + } + } + + Ok(()) +} From ea723f64cd362d4139d0766fc5a74b95166e2ca0 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 7 May 2022 19:11:12 +0800 Subject: [PATCH 106/895] Support `sass` install --- src/cli/tool/mod.rs | 4 ++-- src/tools.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index d5c4581aa..f13c1620e 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -20,9 +20,9 @@ impl Tool { Tool::List {} => { for item in tools::tool_list() { if tools::Tool::from_str(item).unwrap().is_installed() { - println!("{item} [installed]"); + println!("- {item} [installed]"); } else { - println!("{item}"); + println!("- {item}"); } } } diff --git a/src/tools.rs b/src/tools.rs index b37d10cd2..9f96ce0b9 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -53,6 +53,7 @@ impl Tool { pub fn from_str(name: &str) -> Option { match name { "binaryen" => Some(Self::Binaryen), + "sass" => Some(Self::Sass), _ => None, } } @@ -128,7 +129,7 @@ impl Tool { if cfg!(target_os = "windows") { "zip" } else { - "tar.ge" + "tar.gz" } } } @@ -159,7 +160,7 @@ impl Tool { let chunk = chunk_res.context("error reading chunk from download")?; let _ = file.write(chunk.as_ref()).await; } - + // log::info!("temp file path: {:?}", temp_out); Ok(temp_out) } @@ -170,10 +171,8 @@ impl Tool { let dir_name = if self == &Tool::Binaryen { "binaryen-version_105" - } else if self == &Tool::Sass { - "sass-version-1_51" } else { - "" + "dart-sass" }; if self.extension() == "tar.gz" { @@ -181,10 +180,11 @@ impl Tool { let tar = GzDecoder::new(tar_gz); let mut archive = Archive::new(tar); archive.unpack(&tool_path)?; - // println!("{:?} -> {:?}", tool_path.join(dir_name), tool_path.join(self.name())); std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?; } else if self.extension() == "zip" { // decompress the `zip` file + extract_zip(&temp_path, &tool_path)?; + std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?; } Ok(()) From f7f1d90520bf9712172175ad6ccbec41803172f2 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sun, 8 May 2022 00:56:22 +0800 Subject: [PATCH 107/895] Add `sass` support --- src/assets/dioxus.toml | 14 +++++++++++++- src/cli/tool/mod.rs | 7 +++++-- src/tools.rs | 8 +++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 0c57542b8..8f160b293 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -45,4 +45,16 @@ script = [] binaryen = { wasm_opt = true } # use sass auto will auto check sass file and build it. -sass = { auto = true } \ No newline at end of file +[application.tools.sass] + +version = "1.51.0" + +# if auto = true, we will check style array, and translate all sass file to css. +auto = true + +# or you can specify some sass file -> css file +files = [ + # some sass file path + # this file will translate to `/css/test.css` + "/css/test.sass" +] \ No newline at end of file diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index f13c1620e..45c866c40 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -27,7 +27,11 @@ impl Tool { } } Tool::AppPath {} => { - println!("{}", tools::tools_path().to_str().unwrap()); + if let Some(v) = tools::tools_path().to_str() { + println!("{}", v); + } else { + log::error!("Tools path get failed."); + } } Tool::Add { name } => { let tool_list = tools::tool_list(); @@ -58,7 +62,6 @@ impl Tool { log::info!("Tool {name} install successfully!"); } } - Ok(()) } } diff --git a/src/tools.rs b/src/tools.rs index 9f96ce0b9..ae4e58b79 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -201,7 +201,13 @@ impl Tool { command.to_string() } } - Tool::Sass => command.to_string(), + Tool::Sass => { + if cfg!(target_os = "windows") { + format!("{}.bat", command) + } else { + command.to_string() + } + }, }; if !bin_path.join(&command_file).is_file() { From 768a0426d8519073259f9e642bc0b44f75110f52 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 10:31:02 +0800 Subject: [PATCH 108/895] Add `sass` support --- Cargo.toml | 2 ++ src/assets/dioxus.toml | 4 +--- src/builder.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d2bda881f..c869267b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,8 @@ axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } headers = "0.3.7" +walkdir = "2" + # tools download dirs = "4.0.0" reqwest = { version = "0.11", features = ["rustls-tls", "stream", "trust-dns"] } diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 8f160b293..3e82e0c93 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -47,8 +47,6 @@ binaryen = { wasm_opt = true } # use sass auto will auto check sass file and build it. [application.tools.sass] -version = "1.51.0" - # if auto = true, we will check style array, and translate all sass file to css. auto = true @@ -56,5 +54,5 @@ auto = true files = [ # some sass file path # this file will translate to `/css/test.css` - "/css/test.sass" + "/css/test.scss" ] \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index f7f68e2bc..7c3a7e9fb 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,6 +1,7 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, + tools::Tool, DioxusConfig, }; use std::{ @@ -29,6 +30,10 @@ pub fn build(config: &CrateConfig) -> Result<()> { .. } = config; + + // start to build the assets + build_assets(config)?; + let t_start = std::time::Instant::now(); // [1] Build the .wasm module @@ -339,6 +344,49 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { html.replace("{app_title}", &title) } +// this function will build some assets file +// like sass tool resources +fn build_assets(config: &CrateConfig) -> Result<()> { + let dioxus_config = &config.dioxus_config; + let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default(); + + // check sass tool state + let sass = Tool::Sass; + if sass.is_installed() && dioxus_tools.contains_key("sass") { + let sass_conf = dioxus_tools.get("sass").unwrap(); + if let Some(tab) = sass_conf.as_table() { + if tab.contains_key("auto") && tab.get("auto").unwrap().as_bool().unwrap_or(false) { + // if the sass open auto, we need auto-check the assets dir. + let asset_dir = config.asset_dir.clone(); + if asset_dir.is_dir() { + for entry in walkdir::WalkDir::new(asset_dir) + .into_iter() + .filter_map(|e| e.ok()) + { + let temp = entry.path(); + if temp.is_file() { + let suffix = temp.file_name().unwrap().to_str().unwrap(); + let suffix = suffix.split('.').collect::>(); + let suffix: &str = suffix.last().unwrap(); + if suffix == "scss" { + // if file suffix is `scss` we need transform it. + let temp_stem = temp.file_stem().unwrap().to_str().unwrap(); + let target_path = + temp.parent().unwrap().join(format!("{}.css", temp_stem)); + sass.call( + "sass", + vec![temp.to_str().unwrap(), target_path.to_str().unwrap()], + )?; + } + } + } + } + } + } + } + Ok(()) +} + // use binary_install::{Cache, Download}; // /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a From 8b06fe60596371118e47ef71a72627044c17672a Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 13:46:53 +0800 Subject: [PATCH 109/895] Fixed sass tool --- src/assets/dioxus.toml | 4 ++-- src/builder.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 3e82e0c93..105251aa1 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -47,10 +47,10 @@ binaryen = { wasm_opt = true } # use sass auto will auto check sass file and build it. [application.tools.sass] -# if auto = true, we will check style array, and translate all sass file to css. +# auto will check the assets dirs, and auto to transform all scss file to css file. auto = true -# or you can specify some sass file -> css file +# you can specify some scss file -> css file files = [ # some sass file path # this file will translate to `/css/test.css` diff --git a/src/builder.rs b/src/builder.rs index 7c3a7e9fb..0e0cf7e9a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -30,7 +30,6 @@ pub fn build(config: &CrateConfig) -> Result<()> { .. } = config; - // start to build the assets build_assets(config)?; @@ -359,20 +358,21 @@ fn build_assets(config: &CrateConfig) -> Result<()> { // if the sass open auto, we need auto-check the assets dir. let asset_dir = config.asset_dir.clone(); if asset_dir.is_dir() { - for entry in walkdir::WalkDir::new(asset_dir) + for entry in walkdir::WalkDir::new(&asset_dir) .into_iter() .filter_map(|e| e.ok()) { let temp = entry.path(); if temp.is_file() { - let suffix = temp.file_name().unwrap().to_str().unwrap(); - let suffix = suffix.split('.').collect::>(); - let suffix: &str = suffix.last().unwrap(); + let suffix = temp.extension().unwrap().to_str().unwrap(); if suffix == "scss" { // if file suffix is `scss` we need transform it. - let temp_stem = temp.file_stem().unwrap().to_str().unwrap(); - let target_path = - temp.parent().unwrap().join(format!("{}.css", temp_stem)); + let out_file = + format!("{}.css", temp.file_stem().unwrap().to_str().unwrap()); + let target_path = config + .out_dir + .join(temp.strip_prefix(&asset_dir).unwrap().parent().unwrap()) + .join(out_file); sass.call( "sass", vec![temp.to_str().unwrap(), target_path.to_str().unwrap()], From b5ecd09185062724415e9bf7b6b10d7e2c6860e8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 19:22:19 +0800 Subject: [PATCH 110/895] Add `files` list option --- src/assets/dioxus.toml | 2 +- src/builder.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 105251aa1..5f5032e2a 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -50,7 +50,7 @@ binaryen = { wasm_opt = true } # auto will check the assets dirs, and auto to transform all scss file to css file. auto = true -# you can specify some scss file -> css file +# or you can specify some scss file -> css file files = [ # some sass file path # this file will translate to `/css/test.css` diff --git a/src/builder.rs b/src/builder.rs index 0e0cf7e9a..fb0c8088d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -381,6 +381,28 @@ fn build_assets(config: &CrateConfig) -> Result<()> { } } } + } else if tab.contains_key("files") && tab.get("files").unwrap().is_array() { + // check files list. + let list = tab.get("files").unwrap().as_array().unwrap(); + for i in list { + if i.is_str() { + let path = i.as_str().unwrap(); + let path = PathBuf::from(path); + let path = config.asset_dir.join(path); + if path.is_file() { + sass.call( + "sass", + vec![ + path.to_str().unwrap(), + path.parent().unwrap().join(format!( + "{}.css", + path.file_stem().unwrap().to_str().unwrap() + )).to_str().unwrap(), + ], + )?; + } + } + } } } } From 551d2477ffcd84d13cfc4c5d15e1c8033a23a160 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 22:32:47 +0800 Subject: [PATCH 111/895] Add `source_map` option --- src/assets/dioxus.toml | 4 +++- src/builder.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 5f5032e2a..b481193a8 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -55,4 +55,6 @@ files = [ # some sass file path # this file will translate to `/css/test.css` "/css/test.scss" -] \ No newline at end of file +] + +source_map = true \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index fb0c8088d..825a9eebf 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -354,6 +354,17 @@ fn build_assets(config: &CrateConfig) -> Result<()> { if sass.is_installed() && dioxus_tools.contains_key("sass") { let sass_conf = dioxus_tools.get("sass").unwrap(); if let Some(tab) = sass_conf.as_table() { + let source_map = tab.contains_key("source_map"); + let source_map = if source_map && tab.get("source_map").unwrap().is_bool() { + if tab.get("source_map").unwrap().as_bool().unwrap_or_default() { + "--source-map" + } else { + "--no-source-map" + } + } else { + "--no-source-map" + }; + if tab.contains_key("auto") && tab.get("auto").unwrap().as_bool().unwrap_or(false) { // if the sass open auto, we need auto-check the assets dir. let asset_dir = config.asset_dir.clone(); @@ -375,7 +386,11 @@ fn build_assets(config: &CrateConfig) -> Result<()> { .join(out_file); sass.call( "sass", - vec![temp.to_str().unwrap(), target_path.to_str().unwrap()], + vec![ + temp.to_str().unwrap(), + target_path.to_str().unwrap(), + source_map, + ], )?; } } @@ -394,10 +409,15 @@ fn build_assets(config: &CrateConfig) -> Result<()> { "sass", vec![ path.to_str().unwrap(), - path.parent().unwrap().join(format!( - "{}.css", - path.file_stem().unwrap().to_str().unwrap() - )).to_str().unwrap(), + path.parent() + .unwrap() + .join(format!( + "{}.css", + path.file_stem().unwrap().to_str().unwrap() + )) + .to_str() + .unwrap(), + source_map, ], )?; } From 9ddaa773d9ffa8d6274a2731dfdac00223f6b74d Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 22:58:48 +0800 Subject: [PATCH 112/895] Remove `auto` option --- src/builder.rs | 111 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 38 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 825a9eebf..75c83990d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -362,48 +362,54 @@ fn build_assets(config: &CrateConfig) -> Result<()> { "--no-source-map" } } else { - "--no-source-map" + "--source-map" }; - if tab.contains_key("auto") && tab.get("auto").unwrap().as_bool().unwrap_or(false) { - // if the sass open auto, we need auto-check the assets dir. - let asset_dir = config.asset_dir.clone(); - if asset_dir.is_dir() { - for entry in walkdir::WalkDir::new(&asset_dir) - .into_iter() - .filter_map(|e| e.ok()) - { - let temp = entry.path(); - if temp.is_file() { - let suffix = temp.extension().unwrap().to_str().unwrap(); - if suffix == "scss" { - // if file suffix is `scss` we need transform it. - let out_file = - format!("{}.css", temp.file_stem().unwrap().to_str().unwrap()); - let target_path = config - .out_dir - .join(temp.strip_prefix(&asset_dir).unwrap().parent().unwrap()) - .join(out_file); - sass.call( - "sass", - vec![ - temp.to_str().unwrap(), - target_path.to_str().unwrap(), - source_map, - ], - )?; + if tab.contains_key("files") { + if tab.get("files").unwrap().is_str() { + let file = tab.get("files").unwrap().as_str().unwrap().trim(); + + if file == "*" { + // if the sass open auto, we need auto-check the assets dir. + let asset_dir = config.asset_dir.clone(); + if asset_dir.is_dir() { + for entry in walkdir::WalkDir::new(&asset_dir) + .into_iter() + .filter_map(|e| e.ok()) + { + let temp = entry.path(); + if temp.is_file() { + let suffix = temp.extension().unwrap().to_str().unwrap(); + if suffix == "scss" { + // if file suffix is `scss` we need transform it. + let out_file = format!( + "{}.css", + temp.file_stem().unwrap().to_str().unwrap() + ); + let target_path = config + .out_dir + .join( + temp.strip_prefix(&asset_dir) + .unwrap() + .parent() + .unwrap(), + ) + .join(out_file); + sass.call( + "sass", + vec![ + temp.to_str().unwrap(), + target_path.to_str().unwrap(), + source_map, + ], + )?; + } + } } } - } - } - } else if tab.contains_key("files") && tab.get("files").unwrap().is_array() { - // check files list. - let list = tab.get("files").unwrap().as_array().unwrap(); - for i in list { - if i.is_str() { - let path = i.as_str().unwrap(); - let path = PathBuf::from(path); - let path = config.asset_dir.join(path); + } else { + // just transform one file. + let path = config.asset_dir.join(file); if path.is_file() { sass.call( "sass", @@ -422,10 +428,39 @@ fn build_assets(config: &CrateConfig) -> Result<()> { )?; } } + } else if tab.get("files").unwrap().is_array() { + // check files list. + let list = tab.get("files").unwrap().as_array().unwrap(); + for i in list { + if i.is_str() { + let path = i.as_str().unwrap(); + let path = PathBuf::from(path); + let path = config.asset_dir.join(path); + if path.is_file() { + sass.call( + "sass", + vec![ + path.to_str().unwrap(), + path.parent() + .unwrap() + .join(format!( + "{}.css", + path.file_stem().unwrap().to_str().unwrap() + )) + .to_str() + .unwrap(), + source_map, + ], + )?; + } + } + } } } } } + // SASS END + Ok(()) } From ecb846dd24d34c0827bfa3503048bf97a8389fda Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Tue, 10 May 2022 23:00:39 +0800 Subject: [PATCH 113/895] Rename `files` to `input` --- src/assets/dioxus.toml | 12 ++++++------ src/builder.rs | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index b481193a8..a5e849bfb 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -48,13 +48,13 @@ binaryen = { wasm_opt = true } [application.tools.sass] # auto will check the assets dirs, and auto to transform all scss file to css file. -auto = true +input = "*" # or you can specify some scss file -> css file -files = [ - # some sass file path - # this file will translate to `/css/test.css` - "/css/test.scss" -] +# input = [ +# # some sass file path +# # this file will translate to `/css/test.css` +# "/css/test.scss" +# ] source_map = true \ No newline at end of file diff --git a/src/builder.rs b/src/builder.rs index 75c83990d..f9f0bd9bd 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -365,9 +365,9 @@ fn build_assets(config: &CrateConfig) -> Result<()> { "--source-map" }; - if tab.contains_key("files") { - if tab.get("files").unwrap().is_str() { - let file = tab.get("files").unwrap().as_str().unwrap().trim(); + if tab.contains_key("input") { + if tab.get("input").unwrap().is_str() { + let file = tab.get("input").unwrap().as_str().unwrap().trim(); if file == "*" { // if the sass open auto, we need auto-check the assets dir. @@ -428,9 +428,9 @@ fn build_assets(config: &CrateConfig) -> Result<()> { )?; } } - } else if tab.get("files").unwrap().is_array() { + } else if tab.get("input").unwrap().is_array() { // check files list. - let list = tab.get("files").unwrap().as_array().unwrap(); + let list = tab.get("input").unwrap().as_array().unwrap(); for i in list { if i.is_str() { let path = i.as_str().unwrap(); From bf49d526d773cc87449ac343659609c52890f0ac Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 00:27:37 +0800 Subject: [PATCH 114/895] Fixed some problem --- src/builder.rs | 13 ++++++++++++- src/tools.rs | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f9f0bd9bd..77f0838f0 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -409,7 +409,13 @@ fn build_assets(config: &CrateConfig) -> Result<()> { } } else { // just transform one file. - let path = config.asset_dir.join(file); + let path = if &file[0..] == "/" { + &file[1..file.len() - 1] + } else { + file + }; + let path = PathBuf::from(path); + let path = config.asset_dir.join(path); if path.is_file() { sass.call( "sass", @@ -434,6 +440,11 @@ fn build_assets(config: &CrateConfig) -> Result<()> { for i in list { if i.is_str() { let path = i.as_str().unwrap(); + let path = if &path[0..] == "/" { + &path[1..path.len() - 1] + } else { + path + }; let path = PathBuf::from(path); let path = config.asset_dir.join(path); if path.is_file() { diff --git a/src/tools.rs b/src/tools.rs index ae4e58b79..2952a9614 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -207,7 +207,7 @@ impl Tool { } else { command.to_string() } - }, + } }; if !bin_path.join(&command_file).is_file() { @@ -232,7 +232,7 @@ fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> { if !target.exists() { let _ = std::fs::create_dir_all(target)?; } - + for i in 0..zip.len() { let mut file = zip.by_index(i)?; if file.is_dir() { @@ -252,4 +252,4 @@ fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> { } Ok(()) -} +} \ No newline at end of file From c6aa4e332df58c223416fafc62e729574ff8c564 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 10:01:02 +0800 Subject: [PATCH 115/895] Ignore `scss` file in out_dir --- src/builder.rs | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 77f0838f0..25d087191 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -31,7 +31,7 @@ pub fn build(config: &CrateConfig) -> Result<()> { } = config; // start to build the assets - build_assets(config)?; + let ignore_files = build_assets(config)?; let t_start = std::time::Instant::now(); @@ -158,6 +158,13 @@ pub fn build(config: &CrateConfig) -> Result<()> { log::warn!("Error copying dir: {}", _e); } } + for ignore in &ignore_files { + let ignore = ignore.strip_prefix(&config.asset_dir).unwrap(); + let ignore = config.out_dir.join(ignore); + if ignore.is_file() { + std::fs::remove_file(ignore)?; + } + } } } } @@ -345,7 +352,11 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { // this function will build some assets file // like sass tool resources -fn build_assets(config: &CrateConfig) -> Result<()> { +// this function will return a array which file don't need copy to out_dir. +fn build_assets(config: &CrateConfig) -> Result> { + + let mut result = vec![]; + let dioxus_config = &config.dioxus_config; let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default(); @@ -395,14 +406,17 @@ fn build_assets(config: &CrateConfig) -> Result<()> { .unwrap(), ) .join(out_file); - sass.call( + let res = sass.call( "sass", vec![ temp.to_str().unwrap(), target_path.to_str().unwrap(), source_map, ], - )?; + ); + if res.is_ok() { + result.push(temp.to_path_buf()); + } } } } @@ -417,7 +431,7 @@ fn build_assets(config: &CrateConfig) -> Result<()> { let path = PathBuf::from(path); let path = config.asset_dir.join(path); if path.is_file() { - sass.call( + let res = sass.call( "sass", vec![ path.to_str().unwrap(), @@ -431,7 +445,10 @@ fn build_assets(config: &CrateConfig) -> Result<()> { .unwrap(), source_map, ], - )?; + ); + if res.is_ok() { + result.push(path); + } } } } else if tab.get("input").unwrap().is_array() { @@ -448,7 +465,7 @@ fn build_assets(config: &CrateConfig) -> Result<()> { let path = PathBuf::from(path); let path = config.asset_dir.join(path); if path.is_file() { - sass.call( + let res = sass.call( "sass", vec![ path.to_str().unwrap(), @@ -462,7 +479,10 @@ fn build_assets(config: &CrateConfig) -> Result<()> { .unwrap(), source_map, ], - )?; + ); + if res.is_ok() { + result.push(path); + } } } } @@ -472,7 +492,7 @@ fn build_assets(config: &CrateConfig) -> Result<()> { } // SASS END - Ok(()) + Ok(result) } // use binary_install::{Cache, Download}; From dccd82091a0b499527cd435fccf1a088262235e1 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 11:12:23 +0800 Subject: [PATCH 116/895] Fixed `input` option error --- src/builder.rs | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 25d087191..e1ed0a8f1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -354,7 +354,6 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { // like sass tool resources // this function will return a array which file don't need copy to out_dir. fn build_assets(config: &CrateConfig) -> Result> { - let mut result = vec![]; let dioxus_config = &config.dioxus_config; @@ -430,19 +429,23 @@ fn build_assets(config: &CrateConfig) -> Result> { }; let path = PathBuf::from(path); let path = config.asset_dir.join(path); + let out_file = + format!("{}.css", path.file_stem().unwrap().to_str().unwrap()); + let target_path = config + .out_dir + .join( + path.strip_prefix(&config.asset_dir) + .unwrap() + .parent() + .unwrap(), + ) + .join(out_file); if path.is_file() { let res = sass.call( "sass", vec![ path.to_str().unwrap(), - path.parent() - .unwrap() - .join(format!( - "{}.css", - path.file_stem().unwrap().to_str().unwrap() - )) - .to_str() - .unwrap(), + target_path.to_str().unwrap(), source_map, ], ); @@ -464,19 +467,23 @@ fn build_assets(config: &CrateConfig) -> Result> { }; let path = PathBuf::from(path); let path = config.asset_dir.join(path); + let out_file = + format!("{}.css", path.file_stem().unwrap().to_str().unwrap()); + let target_path = config + .out_dir + .join( + path.strip_prefix(&config.asset_dir) + .unwrap() + .parent() + .unwrap(), + ) + .join(out_file); if path.is_file() { let res = sass.call( "sass", vec![ path.to_str().unwrap(), - path.parent() - .unwrap() - .join(format!( - "{}.css", - path.file_stem().unwrap().to_str().unwrap() - )) - .to_str() - .unwrap(), + target_path.to_str().unwrap(), source_map, ], ); From 065da8db6589a1c745392b3973bae127ebecb183 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 11:14:49 +0800 Subject: [PATCH 117/895] Add `sass` desktop build support --- src/builder.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index e1ed0a8f1..ae6e83605 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -177,6 +177,8 @@ pub fn build(config: &CrateConfig) -> Result<()> { pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { log::info!("🚅 Running build [Desktop] command..."); + let ignore_files = build_assets(config)?; + let mut cmd = Command::new("cargo"); cmd.current_dir(&config.crate_dir) .arg("build") @@ -261,6 +263,13 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { log::warn!("Error copying dir: {}", e); } } + for ignore in &ignore_files { + let ignore = ignore.strip_prefix(&config.asset_dir).unwrap(); + let ignore = config.out_dir.join(ignore); + if ignore.is_file() { + std::fs::remove_file(ignore)?; + } + } } } } From 60bb0d9eb9f6a6e10267df85840914afa04d460b Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 11:15:33 +0800 Subject: [PATCH 118/895] Format code --- src/cli/tool/mod.rs | 2 +- src/tools.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/tool/mod.rs b/src/cli/tool/mod.rs index 45c866c40..fde94b29a 100644 --- a/src/cli/tool/mod.rs +++ b/src/cli/tool/mod.rs @@ -27,7 +27,7 @@ impl Tool { } } Tool::AppPath {} => { - if let Some(v) = tools::tools_path().to_str() { + if let Some(v) = tools::tools_path().to_str() { println!("{}", v); } else { log::error!("Tools path get failed."); diff --git a/src/tools.rs b/src/tools.rs index 2952a9614..2ab358d6b 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -252,4 +252,4 @@ fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> { } Ok(()) -} \ No newline at end of file +} From cb650bad8a726c50eacdf8d29669532a5fb75c42 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 11:47:49 +0800 Subject: [PATCH 119/895] Fixed some problem --- src/builder.rs | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index ae6e83605..8f3823a65 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -431,24 +431,19 @@ fn build_assets(config: &CrateConfig) -> Result> { } } else { // just transform one file. - let path = if &file[0..] == "/" { - &file[1..file.len() - 1] + let relative_path = if &file[0..1] == "/" { + &file[1..file.len()] } else { file }; - let path = PathBuf::from(path); - let path = config.asset_dir.join(path); + let path = config.asset_dir.join(relative_path); let out_file = format!("{}.css", path.file_stem().unwrap().to_str().unwrap()); let target_path = config .out_dir - .join( - path.strip_prefix(&config.asset_dir) - .unwrap() - .parent() - .unwrap(), - ) + .join(PathBuf::from(relative_path).parent().unwrap()) .join(out_file); + println!("{:?} -- {:?}", target_path, path); if path.is_file() { let res = sass.call( "sass", @@ -460,6 +455,8 @@ fn build_assets(config: &CrateConfig) -> Result> { ); if res.is_ok() { result.push(path); + } else { + log::error!("{:?}", res); } } } @@ -469,23 +466,17 @@ fn build_assets(config: &CrateConfig) -> Result> { for i in list { if i.is_str() { let path = i.as_str().unwrap(); - let path = if &path[0..] == "/" { - &path[1..path.len() - 1] + let relative_path = if &path[0..1] == "/" { + &path[1..path.len()] } else { path }; - let path = PathBuf::from(path); - let path = config.asset_dir.join(path); + let path = config.asset_dir.join(relative_path); let out_file = format!("{}.css", path.file_stem().unwrap().to_str().unwrap()); let target_path = config .out_dir - .join( - path.strip_prefix(&config.asset_dir) - .unwrap() - .parent() - .unwrap(), - ) + .join(PathBuf::from(relative_path).parent().unwrap()) .join(out_file); if path.is_file() { let res = sass.call( From 7f829c4553eaf45eda2e9c7964ba28cac63723cb Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 11 May 2022 11:50:01 +0800 Subject: [PATCH 120/895] Format code --- src/builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 8f3823a65..e0d3ac285 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -443,7 +443,6 @@ fn build_assets(config: &CrateConfig) -> Result> { .out_dir .join(PathBuf::from(relative_path).parent().unwrap()) .join(out_file); - println!("{:?} -- {:?}", target_path, path); if path.is_file() { let res = sass.call( "sass", From cc56dd19ddbdaf9578ee6f56df7a354bbd2d3bc6 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Thu, 12 May 2022 00:11:51 +0800 Subject: [PATCH 121/895] Add `sass` file extension --- src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index e0d3ac285..cdb431933 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -399,8 +399,8 @@ fn build_assets(config: &CrateConfig) -> Result> { let temp = entry.path(); if temp.is_file() { let suffix = temp.extension().unwrap().to_str().unwrap(); - if suffix == "scss" { - // if file suffix is `scss` we need transform it. + if suffix == "scss" || suffix == "sass" { + // if file suffix is `scss` / `sass` we need transform it. let out_file = format!( "{}.css", temp.file_stem().unwrap().to_str().unwrap() From 87e6ed0a3d13dfb023c185a249ceee3a7a22d9e8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Thu, 12 May 2022 22:49:27 +0800 Subject: [PATCH 122/895] Fixed builder problem --- src/builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index cdb431933..4f6824780 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -398,7 +398,9 @@ fn build_assets(config: &CrateConfig) -> Result> { { let temp = entry.path(); if temp.is_file() { - let suffix = temp.extension().unwrap().to_str().unwrap(); + let suffix = temp.extension(); + if suffix.is_none() { continue; } + let suffix = suffix.unwrap().to_str().unwrap(); if suffix == "scss" || suffix == "sass" { // if file suffix is `scss` / `sass` we need transform it. let out_file = format!( From 51639af48230bb8a4bb7b50105c1bcd270ac0774 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Mon, 6 Jun 2022 00:16:15 +0800 Subject: [PATCH 123/895] feat: add `profile` flag --- src/builder.rs | 5 +++++ src/cli/build/mod.rs | 4 ++++ src/cli/cfg.rs | 8 ++++++++ src/cli/serve/mod.rs | 4 ++++ src/config.rs | 9 +++++++++ 5 files changed, 30 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 4f6824780..31bb96f46 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -49,6 +49,11 @@ pub fn build(config: &CrateConfig) -> Result<()> { cmd.arg("--release"); } + if config.custom_profile.is_some() { + let custom_profile = config.custom_profile.as_ref().unwrap(); + cmd.arg(format!("--profile {}", custom_profile)); + } + match executable { ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 4c043091f..7f8c7b420 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -19,6 +19,10 @@ impl Build { crate_config.as_example(self.build.example.unwrap()); } + if self.build.profile.is_some() { + crate_config.set_profile(self.build.profile.unwrap()); + } + let platform = self.build.platform.unwrap_or_else(|| { crate_config .dioxus_config diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index f5ee45b87..11a1603c7 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -16,6 +16,10 @@ pub struct ConfigOptsBuild { #[clap(long)] pub example: Option, + /// Build with custom profile + #[clap(long)] + pub profile: Option, + /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] pub platform: Option, @@ -36,6 +40,10 @@ pub struct ConfigOptsServe { #[serde(default)] pub release: bool, + /// Build with custom profile + #[clap(long)] + pub profile: Option, + /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] pub platform: Option, diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 85bd92c74..1b79284b7 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -24,6 +24,10 @@ impl Serve { crate_config.as_example(self.serve.example.unwrap()); } + if self.serve.profile.is_some() { + crate_config.set_profile(self.serve.profile.unwrap()); + } + let platform = self.serve.platform.unwrap_or_else(|| { crate_config .dioxus_config diff --git a/src/config.rs b/src/config.rs index 783c72ccd..9679fadaa 100644 --- a/src/config.rs +++ b/src/config.rs @@ -114,6 +114,7 @@ pub struct CrateConfig { pub executable: ExecutableType, pub dioxus_config: DioxusConfig, pub release: bool, + pub custom_profile: Option, } #[derive(Debug, Clone)] @@ -163,6 +164,8 @@ impl CrateConfig { let release = false; + let custom_profile = None; + Ok(Self { out_dir, crate_dir, @@ -173,6 +176,7 @@ impl CrateConfig { executable, release, dioxus_config, + custom_profile, }) } @@ -186,6 +190,11 @@ impl CrateConfig { self } + pub fn set_profile(&mut self, profile: String) -> &mut Self { + self.custom_profile = Some(profile); + self + } + // pub fn with_build_options(&mut self, options: &BuildOptions) { // if let Some(name) = &options.example { // self.as_example(name.clone()); From 6aa609144d4b8dde995749ad2de4aaa8d69f16f4 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Mon, 6 Jun 2022 08:46:16 +0800 Subject: [PATCH 124/895] feat: add `profile` flag --- src/builder.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 31bb96f46..57738b1bc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -51,7 +51,8 @@ pub fn build(config: &CrateConfig) -> Result<()> { if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); - cmd.arg(format!("--profile {}", custom_profile)); + cmd.arg("--profile"); + cmd.arg(custom_profile); } match executable { @@ -194,6 +195,12 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { cmd.arg("--release"); } + if config.custom_profile.is_some() { + let custom_profile = config.custom_profile.as_ref().unwrap(); + cmd.arg("--profile"); + cmd.arg(custom_profile); + } + match &config.executable { crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), From d20e7ab50815014e67871ec2227413a085762690 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:18:22 +0800 Subject: [PATCH 125/895] feat: add `features` flag --- src/builder.rs | 12 ++++++++++++ src/cli/cfg.rs | 8 ++++++++ src/config.rs | 9 ++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 57738b1bc..46d4c15f5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -55,6 +55,12 @@ pub fn build(config: &CrateConfig) -> Result<()> { cmd.arg(custom_profile); } + if config.features.is_some() { + let features_str = config.features.as_ref().unwrap().join(" "); + cmd.arg("--features"); + cmd.arg(features_str); + } + match executable { ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), @@ -201,6 +207,12 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { cmd.arg(custom_profile); } + if config.features.is_some() { + let features_str = config.features.as_ref().unwrap().join(" "); + cmd.arg("--features"); + cmd.arg(features_str); + } + match &config.executable { crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 11a1603c7..b8305e3a8 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -23,6 +23,10 @@ pub struct ConfigOptsBuild { /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] pub platform: Option, + + /// Space separated list of features to activate + #[clap(long)] + pub features: Option>, } #[derive(Clone, Debug, Default, Deserialize, Parser)] @@ -47,6 +51,10 @@ pub struct ConfigOptsServe { /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] pub platform: Option, + + /// Space separated list of features to activate + #[clap(long)] + pub features: Option>, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/config.rs b/src/config.rs index 9679fadaa..6804ae6cd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -115,6 +115,7 @@ pub struct CrateConfig { pub dioxus_config: DioxusConfig, pub release: bool, pub custom_profile: Option, + pub features: Option>, } #[derive(Debug, Clone)] @@ -163,8 +164,8 @@ impl CrateConfig { let executable = ExecutableType::Binary(output_filename); let release = false; - let custom_profile = None; + let features = None; Ok(Self { out_dir, @@ -177,6 +178,7 @@ impl CrateConfig { release, dioxus_config, custom_profile, + features }) } @@ -195,6 +197,11 @@ impl CrateConfig { self } + pub fn set_features(&mut self, features: Vec) -> &mut Self { + self.features = Some(features); + self + } + // pub fn with_build_options(&mut self, options: &BuildOptions) { // if let Some(name) = &options.example { // self.as_example(name.clone()); From 421d2ed2980d4e4d542f1b7b28c31e9ca279a563 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:48:14 +0800 Subject: [PATCH 126/895] feat: add `verbose` flag --- src/builder.rs | 6 ++++++ src/cli/build/mod.rs | 1 + src/cli/cfg.rs | 10 ++++++++++ src/cli/serve/mod.rs | 1 + src/config.rs | 10 +++++++++- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 46d4c15f5..02add84ad 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -48,6 +48,9 @@ pub fn build(config: &CrateConfig) -> Result<()> { if config.release { cmd.arg("--release"); } + if config.verbose { + cmd.arg("--verbose"); + } if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); @@ -200,6 +203,9 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { if config.release { cmd.arg("--release"); } + if config.verbose { + cmd.arg("--verbose"); + } if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 7f8c7b420..661f17a5a 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -14,6 +14,7 @@ impl Build { // change the release state. crate_config.with_release(self.build.release); + crate_config.with_verbose(self.build.verbose); if self.build.example.is_some() { crate_config.as_example(self.build.example.unwrap()); diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index b8305e3a8..26409c370 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -12,6 +12,11 @@ pub struct ConfigOptsBuild { #[serde(default)] pub release: bool, + // Use verbose output [default: false] + #[clap(long)] + #[serde(default)] + pub verbose: bool, + /// Build a example [default: ""] #[clap(long)] pub example: Option, @@ -44,6 +49,11 @@ pub struct ConfigOptsServe { #[serde(default)] pub release: bool, + // Use verbose output [default: false] + #[clap(long)] + #[serde(default)] + pub verbose: bool, + /// Build with custom profile #[clap(long)] pub profile: Option, diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 1b79284b7..d25aa5bad 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -19,6 +19,7 @@ impl Serve { // change the relase state. crate_config.with_release(self.serve.release); + crate_config.with_verbose(self.serve.verbose); if self.serve.example.is_some() { crate_config.as_example(self.serve.example.unwrap()); diff --git a/src/config.rs b/src/config.rs index 6804ae6cd..6e855002b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -114,6 +114,7 @@ pub struct CrateConfig { pub executable: ExecutableType, pub dioxus_config: DioxusConfig, pub release: bool, + pub verbose: bool, pub custom_profile: Option, pub features: Option>, } @@ -164,6 +165,7 @@ impl CrateConfig { let executable = ExecutableType::Binary(output_filename); let release = false; + let verbose = false; let custom_profile = None; let features = None; @@ -178,7 +180,8 @@ impl CrateConfig { release, dioxus_config, custom_profile, - features + features, + verbose, }) } @@ -192,6 +195,11 @@ impl CrateConfig { self } + pub fn with_verbose(&mut self, verbose: bool) -> &mut Self { + self.verbose = verbose; + self + } + pub fn set_profile(&mut self, profile: String) -> &mut Self { self.custom_profile = Some(profile); self From 49b3ef83d33932bb8ee0e15f128f737994ef902a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 09:37:26 -0500 Subject: [PATCH 127/895] create websocket to update rsx and report errors back --- Cargo.toml | 5 + src/hot_reload/mod.rs | 614 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 + src/server/mod.rs | 174 ++++++++++-- 4 files changed, 770 insertions(+), 26 deletions(-) create mode 100644 src/hot_reload/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 21e2dad7e..4acd41463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,11 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" +# hot reload +syn = "1.0" +dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter" } +proc-macro2 = { version = "1.0", features = ["span-locations"] } + [[bin]] path = "src/main.rs" name = "dioxus" diff --git a/src/hot_reload/mod.rs b/src/hot_reload/mod.rs new file mode 100644 index 000000000..d70cda29e --- /dev/null +++ b/src/hot_reload/mod.rs @@ -0,0 +1,614 @@ +use dioxus_rsx::{BodyNode, CallBody}; +use proc_macro2::TokenStream; +use syn::{File, Macro}; + +pub enum DiffResult { + CodeChanged, + RsxChanged(Vec<(Macro, TokenStream)>), +} + +pub fn find_rsx(new: &File, old: &File) -> DiffResult { + let mut rsx_calls = Vec::new(); + if new.items.len() != old.items.len() { + return DiffResult::CodeChanged; + } + for (new, old) in new.items.iter().zip(old.items.iter()) { + if find_rsx_item(new, old, &mut rsx_calls) { + return DiffResult::CodeChanged; + } + } + DiffResult::RsxChanged(rsx_calls) +} + +fn find_rsx_item( + new: &syn::Item, + old: &syn::Item, + rsx_calls: &mut Vec<(Macro, TokenStream)>, +) -> bool { + match (new, old) { + (syn::Item::Const(new_item), syn::Item::Const(old_item)) => { + find_rsx_expr(&new_item.expr, &old_item.expr, rsx_calls) + || new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.const_token != old_item.const_token + || new_item.ident != old_item.ident + || new_item.colon_token != old_item.colon_token + || new_item.ty != old_item.ty + || new_item.eq_token != old_item.eq_token + || new_item.semi_token != old_item.semi_token + } + (syn::Item::Enum(new_item), syn::Item::Enum(old_item)) => { + if new_item.variants.len() != old_item.variants.len() { + return true; + } + for (new_varient, old_varient) in new_item.variants.iter().zip(old_item.variants.iter()) + { + match (&new_varient.discriminant, &old_varient.discriminant) { + (Some((new_eq, new_expr)), Some((old_eq, old_expr))) => { + if find_rsx_expr(new_expr, old_expr, rsx_calls) || new_eq != old_eq { + return true; + } + } + (None, None) => (), + _ => return true, + } + if new_varient.attrs != old_varient.attrs + || new_varient.ident != old_varient.ident + || new_varient.fields != old_varient.fields + { + return true; + } + } + new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.enum_token != old_item.enum_token + || new_item.ident != old_item.ident + || new_item.generics != old_item.generics + || new_item.brace_token != old_item.brace_token + } + (syn::Item::ExternCrate(new_item), syn::Item::ExternCrate(old_item)) => { + old_item != new_item + } + (syn::Item::Fn(new_item), syn::Item::Fn(old_item)) => { + find_rsx_block(&new_item.block, &old_item.block, rsx_calls) + || new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.sig != old_item.sig + } + (syn::Item::ForeignMod(new_item), syn::Item::ForeignMod(old_item)) => old_item != new_item, + (syn::Item::Impl(new_item), syn::Item::Impl(old_item)) => { + if new_item.items.len() != old_item.items.len() { + return true; + } + for (new_item, old_item) in new_item.items.iter().zip(old_item.items.iter()) { + if match (new_item, old_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)) => { + find_rsx_block(&new_item.block, &old_item.block, rsx_calls) + } + (syn::ImplItem::Type(new_item), syn::ImplItem::Type(old_item)) => { + old_item != new_item + } + (syn::ImplItem::Macro(new_item), syn::ImplItem::Macro(old_item)) => { + old_item != new_item + } + _ => true, + } { + return true; + } + } + new_item.attrs != old_item.attrs + || new_item.defaultness != old_item.defaultness + || new_item.unsafety != old_item.unsafety + || new_item.impl_token != old_item.impl_token + || new_item.generics != old_item.generics + || new_item.trait_ != old_item.trait_ + || new_item.self_ty != old_item.self_ty + || new_item.brace_token != old_item.brace_token + } + (syn::Item::Macro(new_item), syn::Item::Macro(old_item)) => old_item != new_item, + (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))) => { + if new_items.len() != old_items.len() { + return true; + } + for (new_item, old_item) in new_items.iter().zip(old_items.iter()) { + if find_rsx_item(new_item, old_item, rsx_calls) { + return true; + } + } + new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.mod_token != old_item.mod_token + || new_item.ident != old_item.ident + || new_item.semi != old_item.semi + } + (None, None) => { + new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.mod_token != old_item.mod_token + || new_item.ident != old_item.ident + || new_item.semi != old_item.semi + } + _ => true, + } + } + (syn::Item::Static(new_item), syn::Item::Static(old_item)) => { + find_rsx_expr(&new_item.expr, &old_item.expr, rsx_calls) + || new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.static_token != old_item.static_token + || new_item.mutability != old_item.mutability + || new_item.ident != old_item.ident + || new_item.colon_token != old_item.colon_token + || new_item.ty != old_item.ty + || new_item.eq_token != old_item.eq_token + || new_item.semi_token != old_item.semi_token + } + (syn::Item::Struct(new_item), syn::Item::Struct(old_item)) => old_item != new_item, + (syn::Item::Trait(new_item), syn::Item::Trait(old_item)) => { + find_rsx_trait(new_item, old_item, rsx_calls) + } + (syn::Item::TraitAlias(new_item), syn::Item::TraitAlias(old_item)) => old_item != new_item, + (syn::Item::Type(new_item), syn::Item::Type(old_item)) => old_item != new_item, + (syn::Item::Union(new_item), syn::Item::Union(old_item)) => old_item != new_item, + (syn::Item::Use(new_item), syn::Item::Use(old_item)) => old_item != new_item, + (syn::Item::Verbatim(_), syn::Item::Verbatim(_)) => false, + _ => return true, + } +} + +fn find_rsx_trait( + new_item: &syn::ItemTrait, + old_item: &syn::ItemTrait, + rsx_calls: &mut Vec<(Macro, TokenStream)>, +) -> bool { + if new_item.items.len() != old_item.items.len() { + return true; + } + for (new_item, old_item) in new_item.items.iter().zip(old_item.items.iter()) { + if match (new_item, old_item) { + (syn::TraitItem::Const(new_item), syn::TraitItem::Const(old_item)) => { + if let (Some((_, new_expr)), Some((_, old_expr))) = + (&new_item.default, &old_item.default) + { + find_rsx_expr(new_expr, old_expr, rsx_calls) + } else { + true + } + } + (syn::TraitItem::Method(new_item), syn::TraitItem::Method(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 { + true + } + } + (syn::TraitItem::Type(new_item), syn::TraitItem::Type(old_item)) => { + old_item != new_item + } + (syn::TraitItem::Macro(new_item), syn::TraitItem::Macro(old_item)) => { + old_item != new_item + } + _ => true, + } { + return true; + } + } + new_item.attrs != old_item.attrs + || new_item.vis != old_item.vis + || new_item.unsafety != old_item.unsafety + || new_item.auto_token != old_item.auto_token + || new_item.ident != old_item.ident + || new_item.generics != old_item.generics + || new_item.colon_token != old_item.colon_token + || new_item.supertraits != old_item.supertraits + || new_item.brace_token != old_item.brace_token +} + +fn find_rsx_block( + new_block: &syn::Block, + old_block: &syn::Block, + rsx_calls: &mut Vec<(Macro, TokenStream)>, +) -> bool { + if new_block.stmts.len() != old_block.stmts.len() { + return true; + } + for (new_stmt, old_stmt) in new_block.stmts.iter().zip(old_block.stmts.iter()) { + if find_rsx_stmt(new_stmt, old_stmt, rsx_calls) { + return true; + } + } + new_block.brace_token != old_block.brace_token +} + +fn find_rsx_stmt( + new_stmt: &syn::Stmt, + old_stmt: &syn::Stmt, + rsx_calls: &mut Vec<(Macro, TokenStream)>, +) -> bool { + 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 + } + (None, None) => false, + _ => true, + } || new_local.attrs != old_local.attrs + || new_local.let_token != old_local.let_token + || new_local.pat != old_local.pat + || new_local.semi_token != old_local.semi_token) + } + (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)) => { + 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 + } + _ => true, + } +} + +fn find_rsx_expr( + new_expr: &syn::Expr, + old_expr: &syn::Expr, + rsx_calls: &mut Vec<(Macro, TokenStream)>, +) -> bool { + match (new_expr, old_expr) { + (syn::Expr::Array(new_expr), syn::Expr::Array(old_expr)) => { + if new_expr.elems.len() != old_expr.elems.len() { + return true; + } + for (new_el, old_el) in new_expr.elems.iter().zip(old_expr.elems.iter()) { + if find_rsx_expr(new_el, old_el, rsx_calls) { + return true; + } + } + new_expr.attrs != old_expr.attrs || new_expr.bracket_token != old_expr.bracket_token + } + (syn::Expr::Assign(new_expr), syn::Expr::Assign(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.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 + || new_expr.async_token != old_expr.async_token + || new_expr.capture != old_expr.capture + } + (syn::Expr::Await(new_expr), syn::Expr::Await(old_expr)) => { + find_rsx_expr(&new_expr.base, &old_expr.base, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.dot_token != old_expr.dot_token + || new_expr.await_token != old_expr.await_token + } + (syn::Expr::Binary(new_expr), syn::Expr::Binary(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::Block(new_expr), syn::Expr::Block(old_expr)) => { + find_rsx_block(&new_expr.block, &old_expr.block, rsx_calls) + || 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)) => { + find_rsx_expr(new_inner, old_inner, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.break_token != old_expr.break_token + || new_expr.label != old_expr.label + } + (None, None) => { + new_expr.attrs != old_expr.attrs + || new_expr.break_token != old_expr.break_token + || new_expr.label != old_expr.label + } + _ => true, + } + } + (syn::Expr::Call(new_expr), syn::Expr::Call(old_expr)) => { + find_rsx_expr(&new_expr.func, &old_expr.func, rsx_calls); + if new_expr.args.len() != old_expr.args.len() { + return true; + } + for (new_arg, old_arg) in new_expr.args.iter().zip(old_expr.args.iter()) { + if find_rsx_expr(new_arg, old_arg, rsx_calls) { + return true; + } + } + new_expr.attrs != old_expr.attrs || new_expr.paren_token != old_expr.paren_token + } + (syn::Expr::Cast(new_expr), syn::Expr::Cast(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.as_token != old_expr.as_token + || new_expr.ty != old_expr.ty + } + (syn::Expr::Closure(new_expr), syn::Expr::Closure(old_expr)) => { + find_rsx_expr(&new_expr.body, &old_expr.body, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.movability != old_expr.movability + || new_expr.asyncness != old_expr.asyncness + || new_expr.capture != old_expr.capture + || new_expr.or1_token != old_expr.or1_token + || new_expr.inputs != old_expr.inputs + || new_expr.or2_token != old_expr.or2_token + || new_expr.output != old_expr.output + } + (syn::Expr::Continue(new_expr), syn::Expr::Continue(old_expr)) => old_expr != new_expr, + (syn::Expr::Field(new_expr), syn::Expr::Field(old_expr)) => { + find_rsx_expr(&new_expr.base, &old_expr.base, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.dot_token != old_expr.dot_token + || new_expr.member != old_expr.member + } + (syn::Expr::ForLoop(new_expr), syn::Expr::ForLoop(old_expr)) => { + find_rsx_block(&new_expr.body, &old_expr.body, rsx_calls) + || find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.label != old_expr.label + || new_expr.for_token != old_expr.for_token + || new_expr.pat != old_expr.pat + || new_expr.in_token != old_expr.in_token + } + (syn::Expr::Group(new_expr), syn::Expr::Group(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + } + (syn::Expr::If(new_expr), syn::Expr::If(old_expr)) => { + if find_rsx_expr(&new_expr.cond, &old_expr.cond, rsx_calls) + || find_rsx_block(&new_expr.then_branch, &old_expr.then_branch, rsx_calls) + { + return true; + } + match (&new_expr.else_branch, &old_expr.else_branch) { + (Some((new_tok, new_else)), Some((old_tok, old_else))) => { + find_rsx_expr(new_else, old_else, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.if_token != old_expr.if_token + || new_expr.cond != old_expr.cond + || new_tok != old_tok + } + (None, None) => { + new_expr.attrs != old_expr.attrs + || new_expr.if_token != old_expr.if_token + || new_expr.cond != old_expr.cond + } + _ => true, + } + } + (syn::Expr::Index(new_expr), syn::Expr::Index(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || find_rsx_expr(&new_expr.index, &old_expr.index, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.bracket_token != old_expr.bracket_token + } + (syn::Expr::Let(new_expr), syn::Expr::Let(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.let_token != old_expr.let_token + || new_expr.pat != old_expr.pat + || new_expr.eq_token != old_expr.eq_token + } + (syn::Expr::Lit(new_expr), syn::Expr::Lit(old_expr)) => old_expr != new_expr, + (syn::Expr::Loop(new_expr), syn::Expr::Loop(old_expr)) => { + find_rsx_block(&new_expr.body, &old_expr.body, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.label != old_expr.label + || new_expr.loop_token != old_expr.loop_token + } + (syn::Expr::Macro(new_expr), syn::Expr::Macro(old_expr)) => { + let new_mac = &new_expr.mac; + let old_mac = &old_expr.mac; + if new_mac.path.get_ident().map(|ident| ident.to_string()) == Some("rsx".to_string()) + && old_mac.path.get_ident().map(|ident| ident.to_string()) + == Some("rsx".to_string()) + { + rsx_calls.push((old_mac.clone(), new_mac.tokens.clone())); + false + } else { + new_expr != old_expr + } + } + (syn::Expr::Match(new_expr), syn::Expr::Match(old_expr)) => { + if find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) { + return true; + } + for (new_arm, old_arm) in new_expr.arms.iter().zip(old_expr.arms.iter()) { + match (&new_arm.guard, &old_arm.guard) { + (Some((new_tok, new_expr)), Some((old_tok, old_expr))) => { + if find_rsx_expr(new_expr, old_expr, rsx_calls) || new_tok != old_tok { + return true; + } + } + (None, None) => (), + _ => return true, + } + if find_rsx_expr(&new_arm.body, &old_arm.body, rsx_calls) + || new_arm.attrs != old_arm.attrs + || new_arm.pat != old_arm.pat + || new_arm.fat_arrow_token != old_arm.fat_arrow_token + || new_arm.comma != old_arm.comma + { + return true; + } + } + new_expr.attrs != old_expr.attrs + || new_expr.match_token != old_expr.match_token + || new_expr.brace_token != old_expr.brace_token + } + (syn::Expr::MethodCall(new_expr), syn::Expr::MethodCall(old_expr)) => { + if find_rsx_expr(&new_expr.receiver, &old_expr.receiver, rsx_calls) { + return true; + } + for (new_arg, old_arg) in new_expr.args.iter().zip(old_expr.args.iter()) { + if find_rsx_expr(new_arg, old_arg, rsx_calls) { + return true; + } + } + new_expr.attrs != old_expr.attrs + || new_expr.dot_token != old_expr.dot_token + || new_expr.method != old_expr.method + || new_expr.turbofish != old_expr.turbofish + || new_expr.paren_token != old_expr.paren_token + } + (syn::Expr::Paren(new_expr), syn::Expr::Paren(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.paren_token != old_expr.paren_token + } + (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) { + (Some(new_expr), Some(old_expr)) => { + if find_rsx_expr(new_expr, old_expr, rsx_calls) { + return true; + } + } + (None, None) => (), + _ => return true, + } + match (&new_expr.to, &old_expr.to) { + (Some(new_inner), Some(old_inner)) => { + find_rsx_expr(new_inner, old_inner, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.limits != old_expr.limits + } + (None, None) => { + new_expr.attrs != old_expr.attrs || new_expr.limits != old_expr.limits + } + _ => true, + } + } + (syn::Expr::Reference(new_expr), syn::Expr::Reference(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.and_token != old_expr.and_token + || new_expr.mutability != old_expr.mutability + } + (syn::Expr::Repeat(new_expr), syn::Expr::Repeat(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || find_rsx_expr(&new_expr.len, &old_expr.len, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.bracket_token != old_expr.bracket_token + || new_expr.semi_token != old_expr.semi_token + } + (syn::Expr::Return(new_expr), syn::Expr::Return(old_expr)) => { + match (&new_expr.expr, &old_expr.expr) { + (Some(new_inner), Some(old_inner)) => { + find_rsx_expr(new_inner, old_inner, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.return_token != old_expr.return_token + } + (None, None) => { + new_expr.attrs != old_expr.attrs + || new_expr.return_token != old_expr.return_token + } + _ => true, + } + } + (syn::Expr::Struct(new_expr), syn::Expr::Struct(old_expr)) => { + match (&new_expr.rest, &old_expr.rest) { + (Some(new_expr), Some(old_expr)) => { + if find_rsx_expr(new_expr, old_expr, rsx_calls) { + return true; + } + } + (None, None) => (), + _ => return true, + } + for (new_field, old_field) in new_expr.fields.iter().zip(old_expr.fields.iter()) { + if find_rsx_expr(&new_field.expr, &old_field.expr, rsx_calls) + || new_field.attrs != old_field.attrs + || new_field.member != old_field.member + || new_field.colon_token != old_field.colon_token + { + return true; + } + } + new_expr.attrs != old_expr.attrs + || new_expr.path != old_expr.path + || new_expr.brace_token != old_expr.brace_token + || new_expr.dot2_token != old_expr.dot2_token + } + (syn::Expr::Try(new_expr), syn::Expr::Try(old_expr)) => { + find_rsx_expr(&new_expr.expr, &old_expr.expr, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.question_token != old_expr.question_token + } + (syn::Expr::TryBlock(new_expr), syn::Expr::TryBlock(old_expr)) => { + find_rsx_block(&new_expr.block, &old_expr.block, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.try_token != old_expr.try_token + } + (syn::Expr::Tuple(new_expr), syn::Expr::Tuple(old_expr)) => { + for (new_el, old_el) in new_expr.elems.iter().zip(old_expr.elems.iter()) { + if find_rsx_expr(new_el, old_el, rsx_calls) { + return true; + } + } + 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 + || new_expr.op != old_expr.op + } + (syn::Expr::Unsafe(new_expr), syn::Expr::Unsafe(old_expr)) => { + find_rsx_block(&new_expr.block, &old_expr.block, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.unsafe_token != old_expr.unsafe_token + } + (syn::Expr::While(new_expr), syn::Expr::While(old_expr)) => { + find_rsx_expr(&new_expr.cond, &old_expr.cond, rsx_calls) + || find_rsx_block(&new_expr.body, &old_expr.body, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.label != old_expr.label + || new_expr.while_token != old_expr.while_token + } + (syn::Expr::Yield(new_expr), syn::Expr::Yield(old_expr)) => { + match (&new_expr.expr, &old_expr.expr) { + (Some(new_inner), Some(old_inner)) => { + find_rsx_expr(new_inner, old_inner, rsx_calls) + || new_expr.attrs != old_expr.attrs + || new_expr.yield_token != old_expr.yield_token + } + (None, None) => { + new_expr.attrs != old_expr.attrs || new_expr.yield_token != old_expr.yield_token + } + _ => true, + } + } + (syn::Expr::Verbatim(_), syn::Expr::Verbatim(_)) => false, + _ => true, + } +} diff --git a/src/lib.rs b/src/lib.rs index 8cd4b1f2d..722b03a06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,6 @@ pub use error::*; pub mod logging; pub use logging::*; + +pub mod hot_reload; +pub use hot_reload::*; diff --git a/src/server/mod.rs b/src/server/mod.rs index 1df13ca6a..230136e54 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,18 +7,28 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; +use std::{fs::File, io::Read}; +use syn::__private::ToTokens; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; -use crate::{builder, serve::Serve, CrateConfig, Result}; +use crate::{builder, find_rsx, serve::Serve, CrateConfig, Result}; use tokio::sync::broadcast; -struct WsRelodState { +use std::collections::HashMap; + +use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; + +struct WsReloadState { update: broadcast::Sender, } +struct HotReloadState { + messages: broadcast::Sender, +} + pub async fn startup(config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); @@ -26,35 +36,20 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let (reload_tx, _) = broadcast::channel(100); - let ws_reload_state = Arc::new(WsRelodState { + let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), }); + let hot_reload_tx = broadcast::channel(100).0; + let hot_reload_state = Arc::new(HotReloadState { + messages: hot_reload_tx.clone(), + }); + let mut last_update_time = chrono::Local::now().timestamp(); // file watcher: check file change let watcher_conf = config.clone(); - let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { - if chrono::Local::now().timestamp() > last_update_time { - log::info!("Start to rebuild project..."); - if builder::build(&watcher_conf).is_ok() { - // change the websocket reload state to true; - // the page will auto-reload. - if watcher_conf - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&watcher_conf); - } - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); - } - } - }) - .unwrap(); + let mut old_files_parsed: HashMap = HashMap::new(); let allow_watch_path = config .dioxus_config .web @@ -63,6 +58,92 @@ pub async fn startup(config: CrateConfig) -> Result<()> { .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); + let crate_dir = config.crate_dir.clone(); + + let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { + if let Ok(evt) = evt { + if let notify::EventKind::Modify(_) = evt.kind { + for path in evt.paths { + log::info!("File changed: {}", path.display()); + let mut file = File::open(path.clone()).unwrap(); + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + if src.is_empty() { + continue; + } + if let Ok(syntax) = syn::parse_file(&src) { + if let Some(old_str) = old_files_parsed.get(path.to_str().unwrap()) { + if let Ok(old) = syn::parse_file(&old_str) { + match find_rsx(&syntax, &old) { + crate::DiffResult::CodeChanged => { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + log::info!("Start to rebuild project..."); + if builder::build(&watcher_conf).is_ok() { + // change the websocket reload state to true; + // the page will auto-reload. + if watcher_conf + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&watcher_conf); + } + let _ = reload_tx.send("reload".into()); + old_files_parsed.insert( + path.to_str().unwrap().to_string(), + src, + ); + last_update_time = chrono::Local::now().timestamp(); + } + } + } + crate::DiffResult::RsxChanged(changed) => { + for (old, new) in changed.into_iter() { + if let Some(hr) = old + .to_token_stream() + .into_iter() + .map(|tree| { + let location = tree.span(); + let start = location.start(); + CodeLocation { + file: path + .strip_prefix(&crate_dir) + .unwrap() + .display() + .to_string(), + line: start.line as u32, + column: start.column as u32 + 1, + } + }) + .min_by(|cl1, cl2| { + cl1.line + .cmp(&cl2.line) + .then(cl1.column.cmp(&cl2.column)) + }) + { + let rsx = new.to_string(); + let _ = hot_reload_tx.send(SetRsxMessage { + location: hr, + new_text: rsx, + }); + } + } + } + } + } + } else { + old_files_parsed.insert(path.to_str().unwrap().to_string(), src); + } + } + } + } + } + }) + .unwrap(); + for sub_path in allow_watch_path { watcher .watch( @@ -115,6 +196,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let router = Router::new() .route("/_dioxus/ws", get(ws_handler)) + .route("/_dioxus/hot_reload", get(hot_reload_handler)) .fallback( get_service(file_service).handle_error(|error: std::io::Error| async move { ( @@ -125,7 +207,12 @@ pub async fn startup(config: CrateConfig) -> Result<()> { ); axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) - .serve(router.layer(Extension(ws_reload_state)).into_make_service()) + .serve( + router + .layer(Extension(ws_reload_state)) + .layer(Extension(hot_reload_state)) + .into_make_service(), + ) .await?; Ok(()) @@ -134,7 +221,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { async fn ws_handler( ws: WebSocketUpgrade, _: Option>, - Extension(state): Extension>, + Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { let mut rx = state.update.subscribe(); @@ -157,3 +244,38 @@ async fn ws_handler( reload_watcher.await.unwrap(); }) } + +async fn hot_reload_handler( + ws: WebSocketUpgrade, + _: Option>, + Extension(state): Extension>, +) -> impl IntoResponse { + ws.on_upgrade(|mut socket| async move { + println!("🔥 Hot Reload WebSocket is connected."); + let mut rx = state.messages.subscribe(); + loop { + let read_set_rsx = rx.recv(); + let read_err = socket.recv(); + tokio::select! { + err = read_err => { + if let Some(Ok(Message::Text(err))) = err { + let error: RecompileReason = serde_json::from_str(&err).unwrap(); + log::error!("{:?}", error); + }; + }, + set_rsx = read_set_rsx => { + if let Ok(rsx) = set_rsx{ + if socket + .send(Message::Text(serde_json::to_string(&rsx).unwrap())) + .await + .is_err() + { + break; + }; + // println!("{:?}", rsx); + } + } + }; + } + }) +} From 3ccd65b582b8320b24c8921829b777084a6d2e1e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 10:35:18 -0500 Subject: [PATCH 128/895] remove unused import --- src/hot_reload/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hot_reload/mod.rs b/src/hot_reload/mod.rs index d70cda29e..3aced9567 100644 --- a/src/hot_reload/mod.rs +++ b/src/hot_reload/mod.rs @@ -1,4 +1,3 @@ -use dioxus_rsx::{BodyNode, CallBody}; use proc_macro2::TokenStream; use syn::{File, Macro}; From 61e9f56816495ad18c367cc72038409e60382ddc Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 11:37:48 -0500 Subject: [PATCH 129/895] automaticly reload when rsx requires it --- src/server/mod.rs | 59 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 230136e54..c4ab60385 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,7 +7,7 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; -use std::{fs::File, io::Read}; +use std::{fs::File, io::Read, sync::Mutex}; use syn::__private::ToTokens; use std::{path::PathBuf, sync::Arc}; @@ -23,10 +23,13 @@ use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage struct WsReloadState { update: broadcast::Sender, + last_file_rebuild: Arc>>, + watcher_config: CrateConfig, } struct HotReloadState { messages: broadcast::Sender, + update: broadcast::Sender, } pub async fn startup(config: CrateConfig) -> Result<()> { @@ -36,20 +39,23 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let (reload_tx, _) = broadcast::channel(100); + let last_file_rebuild = Arc::new(Mutex::new(HashMap::new())); + let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), + last_file_rebuild: last_file_rebuild.clone(), + watcher_config: config.clone(), }); let hot_reload_tx = broadcast::channel(100).0; let hot_reload_state = Arc::new(HotReloadState { messages: hot_reload_tx.clone(), + update: reload_tx.clone(), }); let mut last_update_time = chrono::Local::now().timestamp(); // file watcher: check file change - let watcher_conf = config.clone(); - let mut old_files_parsed: HashMap = HashMap::new(); let allow_watch_path = config .dioxus_config .web @@ -64,7 +70,6 @@ pub async fn startup(config: CrateConfig) -> Result<()> { if let Ok(evt) = evt { if let notify::EventKind::Modify(_) = evt.kind { for path in evt.paths { - log::info!("File changed: {}", path.display()); let mut file = File::open(path.clone()).unwrap(); let mut src = String::new(); file.read_to_string(&mut src).expect("Unable to read file"); @@ -72,35 +77,19 @@ pub async fn startup(config: CrateConfig) -> Result<()> { continue; } if let Ok(syntax) = syn::parse_file(&src) { - if let Some(old_str) = old_files_parsed.get(path.to_str().unwrap()) { + let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); + if let Some(old_str) = last_file_rebuild.get(path.to_str().unwrap()) { if let Ok(old) = syn::parse_file(&old_str) { match find_rsx(&syntax, &old) { crate::DiffResult::CodeChanged => { log::info!("reload required"); if chrono::Local::now().timestamp() > last_update_time { - log::info!("Start to rebuild project..."); - if builder::build(&watcher_conf).is_ok() { - // change the websocket reload state to true; - // the page will auto-reload. - if watcher_conf - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&watcher_conf); - } - let _ = reload_tx.send("reload".into()); - old_files_parsed.insert( - path.to_str().unwrap().to_string(), - src, - ); - last_update_time = chrono::Local::now().timestamp(); - } + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); } } crate::DiffResult::RsxChanged(changed) => { + log::info!("reloading rsx"); for (old, new) in changed.into_iter() { if let Some(hr) = old .to_token_stream() @@ -135,7 +124,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { } } } else { - old_files_parsed.insert(path.to_str().unwrap().to_string(), src); + last_file_rebuild.insert(path.to_str().unwrap().to_string(), src); } } } @@ -229,6 +218,22 @@ async fn ws_handler( loop { let v = rx.recv().await.unwrap(); if v == "reload" { + log::info!("Start to rebuild project..."); + if builder::build(&state.watcher_config).is_ok() { + // change the websocket reload state to true; + // the page will auto-reload. + if state + .watcher_config + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&state.watcher_config); + } + *state.last_file_rebuild.lock().unwrap() = HashMap::new(); + } // ignore the error if socket .send(Message::Text(String::from("reload"))) @@ -261,6 +266,7 @@ async fn hot_reload_handler( if let Some(Ok(Message::Text(err))) = err { let error: RecompileReason = serde_json::from_str(&err).unwrap(); log::error!("{:?}", error); + state.update.send("reload".to_string()).unwrap(); }; }, set_rsx = read_set_rsx => { @@ -272,7 +278,6 @@ async fn hot_reload_handler( { break; }; - // println!("{:?}", rsx); } } }; From f19958d766c5584c89df6d617170e87f275591bd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 11:58:09 -0500 Subject: [PATCH 130/895] move into feature --- Cargo.toml | 10 +-- src/lib.rs | 2 +- src/server/mod.rs | 159 +++++++++++++++++++++++++++------------------- 3 files changed, 100 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4acd41463..770fd7b1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,10 +46,12 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" -# hot reload -syn = "1.0" -dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter" } -proc-macro2 = { version = "1.0", features = ["span-locations"] } +syn = { version = "1.0", optional = true } +dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter", optional = true } +proc-macro2 = { version = "1.0", features = ["span-locations"], optional = true } + +[features] +hot_reload = ["dioxus-rsx-interpreter", "proc-macro2", "syn"] [[bin]] path = "src/main.rs" diff --git a/src/lib.rs b/src/lib.rs index 722b03a06..683b7251a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,5 +19,5 @@ pub use error::*; pub mod logging; pub use logging::*; +#[cfg(feature = "hot_reload")] pub mod hot_reload; -pub use hot_reload::*; diff --git a/src/server/mod.rs b/src/server/mod.rs index c4ab60385..18d50fc57 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,26 +7,34 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; -use std::{fs::File, io::Read, sync::Mutex}; -use syn::__private::ToTokens; +use std::{fs::File, io::Read}; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; -use crate::{builder, find_rsx, serve::Serve, CrateConfig, Result}; +use crate::{builder, serve::Serve, CrateConfig, Result}; use tokio::sync::broadcast; -use std::collections::HashMap; - -use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; +#[cfg(feature = "hot_reload")] +mod hot_reload_improts { + pub use crate::hot_reload::{find_rsx, DiffResult}; + pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; + pub use std::collections::HashMap; + pub use std::sync::Mutex; + pub use syn::__private::ToTokens; +} +#[cfg(feature = "hot_reload")] +use hot_reload_improts::*; struct WsReloadState { update: broadcast::Sender, + #[cfg(feature = "hot_reload")] last_file_rebuild: Arc>>, watcher_config: CrateConfig, } +#[cfg(feature = "hot_reload")] struct HotReloadState { messages: broadcast::Sender, update: broadcast::Sender, @@ -39,19 +47,24 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let (reload_tx, _) = broadcast::channel(100); + #[cfg(feature = "hot_reload")] let last_file_rebuild = Arc::new(Mutex::new(HashMap::new())); - - let ws_reload_state = Arc::new(WsReloadState { - update: reload_tx.clone(), - last_file_rebuild: last_file_rebuild.clone(), - watcher_config: config.clone(), - }); - + #[cfg(feature = "hot_reload")] let hot_reload_tx = broadcast::channel(100).0; + #[cfg(feature = "hot_reload")] let hot_reload_state = Arc::new(HotReloadState { messages: hot_reload_tx.clone(), update: reload_tx.clone(), }); + #[cfg(feature = "hot_reload")] + let crate_dir = config.crate_dir.clone(); + + let ws_reload_state = Arc::new(WsReloadState { + update: reload_tx.clone(), + #[cfg(feature = "hot_reload")] + last_file_rebuild: last_file_rebuild.clone(), + watcher_config: config.clone(), + }); let mut last_update_time = chrono::Local::now().timestamp(); @@ -64,8 +77,6 @@ pub async fn startup(config: CrateConfig) -> Result<()> { .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); - let crate_dir = config.crate_dir.clone(); - let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { if let Ok(evt) = evt { if let notify::EventKind::Modify(_) = evt.kind { @@ -76,55 +87,66 @@ pub async fn startup(config: CrateConfig) -> Result<()> { if src.is_empty() { continue; } - if let Ok(syntax) = syn::parse_file(&src) { - let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); - if let Some(old_str) = last_file_rebuild.get(path.to_str().unwrap()) { - if let Ok(old) = syn::parse_file(&old_str) { - match find_rsx(&syntax, &old) { - crate::DiffResult::CodeChanged => { - log::info!("reload required"); - if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); + #[cfg(feature = "hot_reload")] + { + if let Ok(syntax) = syn::parse_file(&src) { + let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); + if let Some(old_str) = last_file_rebuild.get(path.to_str().unwrap()) { + if let Ok(old) = syn::parse_file(&old_str) { + match find_rsx(&syntax, &old) { + DiffResult::CodeChanged => { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); + } } - } - crate::DiffResult::RsxChanged(changed) => { - log::info!("reloading rsx"); - for (old, new) in changed.into_iter() { - if let Some(hr) = old - .to_token_stream() - .into_iter() - .map(|tree| { - let location = tree.span(); - let start = location.start(); - CodeLocation { - file: path - .strip_prefix(&crate_dir) - .unwrap() - .display() - .to_string(), - line: start.line as u32, - column: start.column as u32 + 1, - } - }) - .min_by(|cl1, cl2| { - cl1.line - .cmp(&cl2.line) - .then(cl1.column.cmp(&cl2.column)) - }) - { - let rsx = new.to_string(); - let _ = hot_reload_tx.send(SetRsxMessage { - location: hr, - new_text: rsx, - }); + DiffResult::RsxChanged(changed) => { + log::info!("reloading rsx"); + for (old, new) in changed.into_iter() { + if let Some(hr) = old + .to_token_stream() + .into_iter() + .map(|tree| { + let location = tree.span(); + let start = location.start(); + CodeLocation { + file: path + .strip_prefix(&crate_dir) + .unwrap() + .display() + .to_string(), + line: start.line as u32, + column: start.column as u32 + 1, + } + }) + .min_by(|cl1, cl2| { + cl1.line + .cmp(&cl2.line) + .then(cl1.column.cmp(&cl2.column)) + }) + { + let rsx = new.to_string(); + let _ = hot_reload_tx.send(SetRsxMessage { + location: hr, + new_text: rsx, + }); + } } } } } + } else { + last_file_rebuild.insert(path.to_str().unwrap().to_string(), src); } - } else { - last_file_rebuild.insert(path.to_str().unwrap().to_string(), src); + } + } + #[cfg(not(feature = "hot_reload"))] + { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); } } } @@ -185,7 +207,6 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let router = Router::new() .route("/_dioxus/ws", get(ws_handler)) - .route("/_dioxus/hot_reload", get(hot_reload_handler)) .fallback( get_service(file_service).handle_error(|error: std::io::Error| async move { ( @@ -194,14 +215,16 @@ pub async fn startup(config: CrateConfig) -> Result<()> { ) }), ); + #[cfg(feature = "hot_reload")] + let router = router.route("/_dioxus/hot_reload", get(hot_reload_handler)); + + let router = router.layer(Extension(ws_reload_state)); + + #[cfg(feature = "hot_reload")] + let router = router.layer(Extension(hot_reload_state)); axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) - .serve( - router - .layer(Extension(ws_reload_state)) - .layer(Extension(hot_reload_state)) - .into_make_service(), - ) + .serve(router.into_make_service()) .await?; Ok(()) @@ -232,7 +255,10 @@ async fn ws_handler( { let _ = Serve::regen_dev_page(&state.watcher_config); } - *state.last_file_rebuild.lock().unwrap() = HashMap::new(); + #[cfg(feature = "hot_reload")] + { + *state.last_file_rebuild.lock().unwrap() = HashMap::new(); + } } // ignore the error if socket @@ -250,6 +276,7 @@ async fn ws_handler( }) } +#[cfg(feature = "hot_reload")] async fn hot_reload_handler( ws: WebSocketUpgrade, _: Option>, From f06920a37ec12fafbff53d766c14b89fd8b21c8a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 12:38:59 -0500 Subject: [PATCH 131/895] search directory .rs files to diff automaticly --- src/server/mod.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 18d50fc57..8670debb1 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,7 +7,10 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; -use std::{fs::File, io::Read}; +use std::{ + fs::{self, File}, + io::{self, Read}, +}; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; @@ -50,6 +53,8 @@ pub async fn startup(config: CrateConfig) -> Result<()> { #[cfg(feature = "hot_reload")] let last_file_rebuild = Arc::new(Mutex::new(HashMap::new())); #[cfg(feature = "hot_reload")] + find_rs_files(&config.crate_dir, &mut *last_file_rebuild.lock().unwrap()).unwrap(); + #[cfg(feature = "hot_reload")] let hot_reload_tx = broadcast::channel(100).0; #[cfg(feature = "hot_reload")] let hot_reload_state = Arc::new(HotReloadState { @@ -215,6 +220,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { ) }), ); + #[cfg(feature = "hot_reload")] let router = router.route("/_dioxus/hot_reload", get(hot_reload_handler)); @@ -257,7 +263,9 @@ async fn ws_handler( } #[cfg(feature = "hot_reload")] { - *state.last_file_rebuild.lock().unwrap() = HashMap::new(); + let mut write = state.last_file_rebuild.lock().unwrap(); + *write = HashMap::new(); + find_rs_files(&state.watcher_config.crate_dir, &mut *write).unwrap(); } } // ignore the error @@ -311,3 +319,23 @@ async fn hot_reload_handler( } }) } + +#[cfg(feature = "hot_reload")] +fn find_rs_files(root: &PathBuf, files: &mut HashMap) -> io::Result<()> { + for entry in fs::read_dir(root)? { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_dir() { + find_rs_files(&path, files)?; + } else { + if path.extension().map(|s| s.to_str()).flatten() == Some("rs") { + let mut file = File::open(path.clone()).unwrap(); + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + files.insert(path.display().to_string(), src); + } + } + } + } + Ok(()) +} From aa9f5a1a425c0e07e234ac8e594d041b53fb79f4 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 12:44:07 -0500 Subject: [PATCH 132/895] clean up imports --- src/server/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 8670debb1..9c0c86fd6 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,10 +7,7 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; -use std::{ - fs::{self, File}, - io::{self, Read}, -}; +use std::{fs::File, io::Read}; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; @@ -25,6 +22,7 @@ mod hot_reload_improts { pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; pub use std::collections::HashMap; pub use std::sync::Mutex; + pub use std::{fs, io}; pub use syn::__private::ToTokens; } #[cfg(feature = "hot_reload")] From 1d29f66cfc40cbd33065a193cbc013694cfebf0f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Jun 2022 13:00:28 -0500 Subject: [PATCH 133/895] use log::info instead of print --- src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 9c0c86fd6..95026d768 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -289,7 +289,7 @@ async fn hot_reload_handler( Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { - println!("🔥 Hot Reload WebSocket is connected."); + log::info!("🔥 Hot Reload WebSocket connected"); let mut rx = state.messages.subscribe(); loop { let read_set_rsx = rx.recv(); From 0c4028ad5270281e0893dd8e919fdebb3407b44c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 10 Jun 2022 19:18:02 -0500 Subject: [PATCH 134/895] close websocket on disconnect --- src/server/mod.rs | 54 ++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 95026d768..3506112f2 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -291,30 +291,40 @@ async fn hot_reload_handler( ws.on_upgrade(|mut socket| async move { log::info!("🔥 Hot Reload WebSocket connected"); let mut rx = state.messages.subscribe(); - loop { - let read_set_rsx = rx.recv(); - let read_err = socket.recv(); - tokio::select! { - err = read_err => { - if let Some(Ok(Message::Text(err))) = err { - let error: RecompileReason = serde_json::from_str(&err).unwrap(); - log::error!("{:?}", error); - state.update.send("reload".to_string()).unwrap(); - }; - }, - set_rsx = read_set_rsx => { - if let Ok(rsx) = set_rsx{ - if socket - .send(Message::Text(serde_json::to_string(&rsx).unwrap())) - .await - .is_err() - { + let hot_reload_handle = tokio::spawn(async move { + loop { + let read_set_rsx = rx.recv(); + let read_err = socket.recv(); + tokio::select! { + err = read_err => { + if let Some(Ok(err)) = err { + if let Message::Text(err) = err { + let error: RecompileReason = serde_json::from_str(&err).unwrap(); + log::error!("{:?}", error); + if state.update.send("reload".to_string()).is_err() { + break; + } + } + } else { break; - }; + } + }, + set_rsx = read_set_rsx => { + if let Ok(rsx) = set_rsx { + if socket + .send(Message::Text(serde_json::to_string(&rsx).unwrap())) + .await + .is_err() + { + break; + }; + } } - } - }; - } + }; + } + }); + + hot_reload_handle.await.unwrap(); }) } From d1c619e5dc9409eb358dfaf141458a5b38edc02b Mon Sep 17 00:00:00 2001 From: xTeKc <81730792+xTeKc@users.noreply.github.com> Date: Sun, 12 Jun 2022 03:31:13 -0400 Subject: [PATCH 135/895] update edition --- rustfmt.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 9071fb4b5..39b98f125 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,8 +1,8 @@ version = "Two" -edition = "2018" +edition = "2021" imports_granularity = "Crate" #use_small_heuristics = "Max" #control_brace_style = "ClosingNextLine" normalize_comments = true -format_code_in_doc_comments = true \ No newline at end of file +format_code_in_doc_comments = true From f287e757611ac2a84a8622bcf9b4a3d3cf60294b Mon Sep 17 00:00:00 2001 From: xTeKc <81730792+xTeKc@users.noreply.github.com> Date: Sun, 12 Jun 2022 03:31:35 -0400 Subject: [PATCH 136/895] update edition --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c869267b1..24493e787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "dioxus-cli" version = "0.1.4" authors = ["Jonathan Kelley"] -edition = "2018" +edition = "2021" description = "CLI tool for developing, testing, and publishing Dioxus apps" license = "MIT/Apache-2.0" From bfab711010dd4f508930c3ce6af8f39c65c6c025 Mon Sep 17 00:00:00 2001 From: xTeKc <81730792+xTeKc@users.noreply.github.com> Date: Sun, 12 Jun 2022 03:35:25 -0400 Subject: [PATCH 137/895] force closure to take ownership --- src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 1df13ca6a..ada3e10c7 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -79,7 +79,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let file_service_config = config.clone(); let file_service = ServiceBuilder::new() .and_then( - |response: Response| async move { + move |response: Response| async move { let response = if file_service_config .dioxus_config .web From b3db5469c36b143d024b6b828cebcef261740510 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 13 Jun 2022 15:33:49 -0500 Subject: [PATCH 138/895] ignore files that have not been changed recently when checking for changes initially --- src/hot_reload/mod.rs | 4 +- src/server/mod.rs | 206 +++++++++++++++++++++++++++++------------- 2 files changed, 145 insertions(+), 65 deletions(-) diff --git a/src/hot_reload/mod.rs b/src/hot_reload/mod.rs index 3aced9567..8297fedb9 100644 --- a/src/hot_reload/mod.rs +++ b/src/hot_reload/mod.rs @@ -426,7 +426,9 @@ fn find_rsx_expr( && old_mac.path.get_ident().map(|ident| ident.to_string()) == Some("rsx".to_string()) { - rsx_calls.push((old_mac.clone(), new_mac.tokens.clone())); + if old_mac != new_mac { + rsx_calls.push((old_mac.clone(), new_mac.tokens.clone())); + } false } else { new_expr != old_expr diff --git a/src/server/mod.rs b/src/server/mod.rs index 3506112f2..a0bdf24b0 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,7 +7,6 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; -use std::{fs::File, io::Read}; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; @@ -20,9 +19,12 @@ use tokio::sync::broadcast; mod hot_reload_improts { pub use crate::hot_reload::{find_rsx, DiffResult}; pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; + pub use proc_macro2::TokenStream; pub use std::collections::HashMap; pub use std::sync::Mutex; - pub use std::{fs, io}; + pub use std::time::SystemTime; + pub use std::{fs, io, path::Path}; + pub use std::{fs::File, io::Read}; pub use syn::__private::ToTokens; } #[cfg(feature = "hot_reload")] @@ -31,7 +33,7 @@ use hot_reload_improts::*; struct WsReloadState { update: broadcast::Sender, #[cfg(feature = "hot_reload")] - last_file_rebuild: Arc>>, + last_file_rebuild: Arc>, watcher_config: CrateConfig, } @@ -39,6 +41,47 @@ struct WsReloadState { struct HotReloadState { messages: broadcast::Sender, update: broadcast::Sender, + last_file_rebuild: Arc>, + watcher_config: CrateConfig, +} + +#[cfg(feature = "hot_reload")] +struct FileMap { + map: HashMap, + last_updated_time: std::time::SystemTime, +} + +#[cfg(feature = "hot_reload")] +impl FileMap { + fn new(path: PathBuf) -> Self { + fn find_rs_files(root: PathBuf) -> io::Result> { + let mut files = HashMap::new(); + if root.is_dir() { + let mut handles = Vec::new(); + for entry in fs::read_dir(root)? { + if let Ok(entry) = entry { + let path = entry.path(); + handles.push(std::thread::spawn(move || find_rs_files(path))); + } + } + for handle in handles { + files.extend(handle.join().unwrap()?); + } + } else { + if root.extension().map(|s| s.to_str()).flatten() == Some("rs") { + let mut file = File::open(root.clone()).unwrap(); + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + files.insert(root, src); + } + } + Ok(files) + } + Self { + last_updated_time: SystemTime::now(), + map: find_rs_files(path).unwrap(), + } + } } pub async fn startup(config: CrateConfig) -> Result<()> { @@ -49,15 +92,15 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let (reload_tx, _) = broadcast::channel(100); #[cfg(feature = "hot_reload")] - let last_file_rebuild = Arc::new(Mutex::new(HashMap::new())); - #[cfg(feature = "hot_reload")] - find_rs_files(&config.crate_dir, &mut *last_file_rebuild.lock().unwrap()).unwrap(); + let last_file_rebuild = Arc::new(Mutex::new(FileMap::new(config.crate_dir.clone()))); #[cfg(feature = "hot_reload")] let hot_reload_tx = broadcast::channel(100).0; #[cfg(feature = "hot_reload")] let hot_reload_state = Arc::new(HotReloadState { messages: hot_reload_tx.clone(), update: reload_tx.clone(), + last_file_rebuild: last_file_rebuild.clone(), + watcher_config: config.clone(), }); #[cfg(feature = "hot_reload")] let crate_dir = config.crate_dir.clone(); @@ -83,18 +126,21 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { if let Ok(evt) = evt { if let notify::EventKind::Modify(_) = evt.kind { - for path in evt.paths { - let mut file = File::open(path.clone()).unwrap(); - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - if src.is_empty() { - continue; - } - #[cfg(feature = "hot_reload")] - { + #[cfg(feature = "hot_reload")] + { + for path in evt.paths { + let mut file = File::open(path.clone()).unwrap(); + if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { + continue; + } + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + if src.is_empty() { + continue; + } if let Ok(syntax) = syn::parse_file(&src) { let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); - if let Some(old_str) = last_file_rebuild.get(path.to_str().unwrap()) { + if let Some(old_str) = last_file_rebuild.map.get(&path) { if let Ok(old) = syn::parse_file(&old_str) { match find_rsx(&syntax, &old) { DiffResult::CodeChanged => { @@ -107,28 +153,13 @@ pub async fn startup(config: CrateConfig) -> Result<()> { DiffResult::RsxChanged(changed) => { log::info!("reloading rsx"); for (old, new) in changed.into_iter() { - if let Some(hr) = old - .to_token_stream() - .into_iter() - .map(|tree| { - let location = tree.span(); - let start = location.start(); - CodeLocation { - file: path - .strip_prefix(&crate_dir) - .unwrap() - .display() - .to_string(), - line: start.line as u32, - column: start.column as u32 + 1, - } - }) - .min_by(|cl1, cl2| { - cl1.line - .cmp(&cl2.line) - .then(cl1.column.cmp(&cl2.column)) - }) - { + if let Some(hr) = get_min_location( + &path + .strip_prefix(&crate_dir) + .unwrap() + .to_path_buf(), + old.to_token_stream(), + ) { let rsx = new.to_string(); let _ = hot_reload_tx.send(SetRsxMessage { location: hr, @@ -140,17 +171,17 @@ pub async fn startup(config: CrateConfig) -> Result<()> { } } } else { - last_file_rebuild.insert(path.to_str().unwrap().to_string(), src); + *last_file_rebuild = FileMap::new(crate_dir.clone()); } } } - #[cfg(not(feature = "hot_reload"))] - { - log::info!("reload required"); - if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); - } + } + #[cfg(not(feature = "hot_reload"))] + { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); } } } @@ -262,8 +293,7 @@ async fn ws_handler( #[cfg(feature = "hot_reload")] { let mut write = state.last_file_rebuild.lock().unwrap(); - *write = HashMap::new(); - find_rs_files(&state.watcher_config.crate_dir, &mut *write).unwrap(); + *write = FileMap::new(state.watcher_config.crate_dir.clone()); } } // ignore the error @@ -290,6 +320,59 @@ async fn hot_reload_handler( ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { log::info!("🔥 Hot Reload WebSocket connected"); + { + log::info!("Searching files for changes since last run..."); + // update any files that changed before the websocket connected. + let mut messages = Vec::new(); + + { + let handle = state.last_file_rebuild.lock().unwrap(); + let update_time = handle.last_updated_time.clone(); + for (k, v) in handle.map.iter() { + let mut file = File::open(k).unwrap(); + if let Ok(md) = file.metadata() { + if let Ok(time) = md.modified() { + if time < update_time { + continue; + } + } + } + let mut new = String::new(); + file.read_to_string(&mut new).expect("Unable to read file"); + if let Ok(new) = syn::parse_file(&new) { + if let Ok(old) = syn::parse_file(&v) { + if let DiffResult::RsxChanged(changed) = find_rsx(&new, &old) { + for (old, new) in changed.into_iter() { + if let Some(hr) = get_min_location( + k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), + old.to_token_stream(), + ) { + let rsx = new.to_string(); + let msg = SetRsxMessage { + location: hr, + new_text: rsx, + }; + messages.push(msg); + } + } + } + } + } + } + } + + for msg in &messages { + if socket + .send(Message::Text(serde_json::to_string(msg).unwrap())) + .await + .is_err() + { + return; + } + } + log::info!("Updated page"); + } + let mut rx = state.messages.subscribe(); let hot_reload_handle = tokio::spawn(async move { loop { @@ -329,21 +412,16 @@ async fn hot_reload_handler( } #[cfg(feature = "hot_reload")] -fn find_rs_files(root: &PathBuf, files: &mut HashMap) -> io::Result<()> { - for entry in fs::read_dir(root)? { - if let Ok(entry) = entry { - let path = entry.path(); - if path.is_dir() { - find_rs_files(&path, files)?; - } else { - if path.extension().map(|s| s.to_str()).flatten() == Some("rs") { - let mut file = File::open(path.clone()).unwrap(); - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - files.insert(path.display().to_string(), src); - } +fn get_min_location(path: &Path, ts: TokenStream) -> Option { + ts.into_iter() + .map(|tree| { + let location = tree.span(); + let start = location.start(); + CodeLocation { + file: path.display().to_string(), + line: start.line as u32, + column: start.column as u32 + 1, } - } - } - Ok(()) + }) + .min_by(|cl1, cl2| cl1.line.cmp(&cl2.line).then(cl1.column.cmp(&cl2.column))) } From 712d258496415f839b389da8163d5634a36e15f1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Jun 2022 07:31:37 -0500 Subject: [PATCH 139/895] clean up config statements --- src/hot_reload/mod.rs | 4 +- src/server/hot_reload.rs | 174 ++++++++++++++++++ src/server/mod.rs | 383 +++++++++++++++------------------------ 3 files changed, 321 insertions(+), 240 deletions(-) create mode 100644 src/server/hot_reload.rs diff --git a/src/hot_reload/mod.rs b/src/hot_reload/mod.rs index 8297fedb9..3aced9567 100644 --- a/src/hot_reload/mod.rs +++ b/src/hot_reload/mod.rs @@ -426,9 +426,7 @@ fn find_rsx_expr( && old_mac.path.get_ident().map(|ident| ident.to_string()) == Some("rsx".to_string()) { - if old_mac != new_mac { - rsx_calls.push((old_mac.clone(), new_mac.tokens.clone())); - } + rsx_calls.push((old_mac.clone(), new_mac.tokens.clone())); false } else { new_expr != old_expr diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs new file mode 100644 index 000000000..661d249e6 --- /dev/null +++ b/src/server/hot_reload.rs @@ -0,0 +1,174 @@ +use axum::{ + extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, + response::IntoResponse, +}; + +use std::{path::PathBuf, sync::Arc}; + +pub use crate::hot_reload::{find_rsx, DiffResult}; +use crate::CrateConfig; +pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; +pub use proc_macro2::TokenStream; +pub use std::collections::HashMap; +pub use std::sync::Mutex; +pub use std::time::SystemTime; +pub use std::{fs, io, path::Path}; +pub use std::{fs::File, io::Read}; +pub use syn::__private::ToTokens; +use tokio::sync::broadcast; + +pub struct HotReloadState { + pub messages: broadcast::Sender, + pub update: broadcast::Sender, + pub last_file_rebuild: Arc>, + pub watcher_config: CrateConfig, +} + +pub struct FileMap { + pub map: HashMap, + pub last_updated_time: std::time::SystemTime, +} + +impl FileMap { + pub fn new(path: PathBuf) -> Self { + fn find_rs_files(root: PathBuf) -> io::Result> { + let mut files = HashMap::new(); + if root.is_dir() { + let mut handles = Vec::new(); + for entry in fs::read_dir(root)? { + if let Ok(entry) = entry { + let path = entry.path(); + handles.push(std::thread::spawn(move || find_rs_files(path))); + } + } + for handle in handles { + files.extend(handle.join().unwrap()?); + } + } else { + if root.extension().map(|s| s.to_str()).flatten() == Some("rs") { + let mut file = File::open(root.clone()).unwrap(); + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + files.insert(root, src); + } + } + Ok(files) + } + Self { + last_updated_time: SystemTime::now(), + map: find_rs_files(path).unwrap(), + } + } +} + +pub async fn hot_reload_handler( + ws: WebSocketUpgrade, + _: Option>, + Extension(state): Extension>, +) -> impl IntoResponse { + ws.on_upgrade(|mut socket| async move { + log::info!("🔥 Hot Reload WebSocket connected"); + { + log::info!("Searching files for changes since last run..."); + // update any files that changed before the websocket connected. + let mut messages = Vec::new(); + + { + let handle = state.last_file_rebuild.lock().unwrap(); + let update_time = handle.last_updated_time.clone(); + for (k, v) in handle.map.iter() { + let mut file = File::open(k).unwrap(); + if let Ok(md) = file.metadata() { + if let Ok(time) = md.modified() { + if time < update_time { + continue; + } + } + } + let mut new = String::new(); + file.read_to_string(&mut new).expect("Unable to read file"); + if let Ok(new) = syn::parse_file(&new) { + if let Ok(old) = syn::parse_file(&v) { + if let DiffResult::RsxChanged(changed) = find_rsx(&new, &old) { + for (old, new) in changed.into_iter() { + if let Some(hr) = get_min_location( + k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), + old.to_token_stream(), + ) { + let rsx = new.to_string(); + let msg = SetRsxMessage { + location: hr, + new_text: rsx, + }; + messages.push(msg); + } + } + } + } + } + } + } + + for msg in &messages { + if socket + .send(Message::Text(serde_json::to_string(msg).unwrap())) + .await + .is_err() + { + return; + } + } + log::info!("Updated page"); + } + + let mut rx = state.messages.subscribe(); + let hot_reload_handle = tokio::spawn(async move { + loop { + let read_set_rsx = rx.recv(); + let read_err = socket.recv(); + tokio::select! { + err = read_err => { + if let Some(Ok(err)) = err { + if let Message::Text(err) = err { + let error: RecompileReason = serde_json::from_str(&err).unwrap(); + log::error!("{:?}", error); + if state.update.send("reload".to_string()).is_err() { + break; + } + } + } else { + break; + } + }, + set_rsx = read_set_rsx => { + if let Ok(rsx) = set_rsx { + if socket + .send(Message::Text(serde_json::to_string(&rsx).unwrap())) + .await + .is_err() + { + break; + }; + } + } + }; + } + }); + + hot_reload_handle.await.unwrap(); + }) +} + +pub fn get_min_location(path: &Path, ts: TokenStream) -> Option { + ts.into_iter() + .map(|tree| { + let location = tree.span(); + let start = location.start(); + CodeLocation { + file: path.display().to_string(), + line: start.line as u32, + column: start.column as u32 + 1, + } + }) + .min_by(|cl1, cl2| cl1.line.cmp(&cl2.line).then(cl1.column.cmp(&cl2.column))) +} diff --git a/src/server/mod.rs b/src/server/mod.rs index a0bdf24b0..262dbf17d 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -16,19 +16,9 @@ use crate::{builder, serve::Serve, CrateConfig, Result}; use tokio::sync::broadcast; #[cfg(feature = "hot_reload")] -mod hot_reload_improts { - pub use crate::hot_reload::{find_rsx, DiffResult}; - pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; - pub use proc_macro2::TokenStream; - pub use std::collections::HashMap; - pub use std::sync::Mutex; - pub use std::time::SystemTime; - pub use std::{fs, io, path::Path}; - pub use std::{fs::File, io::Read}; - pub use syn::__private::ToTokens; -} +mod hot_reload; #[cfg(feature = "hot_reload")] -use hot_reload_improts::*; +use hot_reload::*; struct WsReloadState { update: broadcast::Sender, @@ -38,76 +28,24 @@ struct WsReloadState { } #[cfg(feature = "hot_reload")] -struct HotReloadState { - messages: broadcast::Sender, - update: broadcast::Sender, - last_file_rebuild: Arc>, - watcher_config: CrateConfig, -} - -#[cfg(feature = "hot_reload")] -struct FileMap { - map: HashMap, - last_updated_time: std::time::SystemTime, -} - -#[cfg(feature = "hot_reload")] -impl FileMap { - fn new(path: PathBuf) -> Self { - fn find_rs_files(root: PathBuf) -> io::Result> { - let mut files = HashMap::new(); - if root.is_dir() { - let mut handles = Vec::new(); - for entry in fs::read_dir(root)? { - if let Ok(entry) = entry { - let path = entry.path(); - handles.push(std::thread::spawn(move || find_rs_files(path))); - } - } - for handle in handles { - files.extend(handle.join().unwrap()?); - } - } else { - if root.extension().map(|s| s.to_str()).flatten() == Some("rs") { - let mut file = File::open(root.clone()).unwrap(); - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - files.insert(root, src); - } - } - Ok(files) - } - Self { - last_updated_time: SystemTime::now(), - map: find_rs_files(path).unwrap(), - } - } -} - pub async fn startup(config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); - let (reload_tx, _) = broadcast::channel(100); - - #[cfg(feature = "hot_reload")] let last_file_rebuild = Arc::new(Mutex::new(FileMap::new(config.crate_dir.clone()))); - #[cfg(feature = "hot_reload")] let hot_reload_tx = broadcast::channel(100).0; - #[cfg(feature = "hot_reload")] let hot_reload_state = Arc::new(HotReloadState { messages: hot_reload_tx.clone(), update: reload_tx.clone(), last_file_rebuild: last_file_rebuild.clone(), watcher_config: config.clone(), }); - #[cfg(feature = "hot_reload")] - let crate_dir = config.crate_dir.clone(); + let crate_dir = config.crate_dir.clone(); let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), - #[cfg(feature = "hot_reload")] + last_file_rebuild: last_file_rebuild.clone(), watcher_config: config.clone(), }); @@ -125,63 +63,49 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { if let Ok(evt) = evt { - if let notify::EventKind::Modify(_) = evt.kind { - #[cfg(feature = "hot_reload")] - { - for path in evt.paths { - let mut file = File::open(path.clone()).unwrap(); - if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { - continue; - } - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - if src.is_empty() { - continue; - } - if let Ok(syntax) = syn::parse_file(&src) { - let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); - if let Some(old_str) = last_file_rebuild.map.get(&path) { - if let Ok(old) = syn::parse_file(&old_str) { - match find_rsx(&syntax, &old) { - DiffResult::CodeChanged => { - log::info!("reload required"); - if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); - } - } - DiffResult::RsxChanged(changed) => { - log::info!("reloading rsx"); - for (old, new) in changed.into_iter() { - if let Some(hr) = get_min_location( - &path - .strip_prefix(&crate_dir) - .unwrap() - .to_path_buf(), - old.to_token_stream(), - ) { - let rsx = new.to_string(); - let _ = hot_reload_tx.send(SetRsxMessage { - location: hr, - new_text: rsx, - }); - } - } + for path in evt.paths { + let mut file = File::open(path.clone()).unwrap(); + if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { + continue; + } + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + if src.is_empty() { + continue; + } + // find changes to the rsx in the file + if let Ok(syntax) = syn::parse_file(&src) { + let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); + if let Some(old_str) = last_file_rebuild.map.get(&path) { + if let Ok(old) = syn::parse_file(&old_str) { + match find_rsx(&syntax, &old) { + DiffResult::CodeChanged => { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); + } + } + DiffResult::RsxChanged(changed) => { + log::info!("reloading rsx"); + for (old, new) in changed.into_iter() { + if let Some(hr) = get_min_location( + &path.strip_prefix(&crate_dir).unwrap().to_path_buf(), + old.to_token_stream(), + ) { + let rsx = new.to_string(); + let _ = hot_reload_tx.send(SetRsxMessage { + location: hr, + new_text: rsx, + }); } } } - } else { - *last_file_rebuild = FileMap::new(crate_dir.clone()); } } - } - } - #[cfg(not(feature = "hot_reload"))] - { - log::info!("reload required"); - if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); + } else { + // if this is a new file, rebuild the project + *last_file_rebuild = FileMap::new(crate_dir.clone()); } } } @@ -250,13 +174,112 @@ pub async fn startup(config: CrateConfig) -> Result<()> { }), ); - #[cfg(feature = "hot_reload")] - let router = router.route("/_dioxus/hot_reload", get(hot_reload_handler)); + let router = router + .route("/_dioxus/hot_reload", get(hot_reload_handler)) + .layer(Extension(ws_reload_state)) + .layer(Extension(hot_reload_state)); - let router = router.layer(Extension(ws_reload_state)); + axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) + .serve(router.into_make_service()) + .await?; - #[cfg(feature = "hot_reload")] - let router = router.layer(Extension(hot_reload_state)); + Ok(()) +} + +#[cfg(not(feature = "hot_reload"))] +pub async fn startup(config: CrateConfig) -> Result<()> { + log::info!("🚀 Starting development server..."); + + let dist_path = config.out_dir.clone(); + + let (reload_tx, _) = broadcast::channel(100); + + let ws_reload_state = Arc::new(WsReloadState { + update: reload_tx.clone(), + watcher_config: config.clone(), + }); + + let mut last_update_time = chrono::Local::now().timestamp(); + + // file watcher: check file change + let allow_watch_path = config + .dioxus_config + .web + .watcher + .watch_path + .clone() + .unwrap_or_else(|| vec![PathBuf::from("src")]); + + let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { + log::info!("reload required"); + if chrono::Local::now().timestamp() > last_update_time { + let _ = reload_tx.send("reload".into()); + last_update_time = chrono::Local::now().timestamp(); + } + }) + .unwrap(); + + for sub_path in allow_watch_path { + watcher + .watch( + &config.crate_dir.join(sub_path), + notify::RecursiveMode::Recursive, + ) + .unwrap(); + } + + // start serve dev-server at 0.0.0.0:8080 + let port = "8080"; + log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); + + let file_service_config = config.clone(); + let file_service = ServiceBuilder::new() + .and_then( + |response: Response| async move { + let response = if file_service_config + .dioxus_config + .web + .watcher + .index_on_404 + .unwrap_or(false) + && response.status() == StatusCode::NOT_FOUND + { + let body = Full::from( + // TODO: Cache/memoize this. + std::fs::read_to_string( + file_service_config + .crate_dir + .join(file_service_config.out_dir) + .join("index.html"), + ) + .ok() + .unwrap(), + ) + .map_err(|err| match err {}) + .boxed(); + Response::builder() + .status(StatusCode::OK) + .body(body) + .unwrap() + } else { + response.map(|body| body.boxed()) + }; + Ok(response) + }, + ) + .service(ServeDir::new((&config.crate_dir).join(&dist_path))); + + let router = Router::new() + .route("/_dioxus/ws", get(ws_handler)) + .fallback( + get_service(file_service).handle_error(|error: std::io::Error| async move { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + ) + }), + ) + .layer(Extension(ws_reload_state)); axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) .serve(router.into_make_service()) @@ -311,117 +334,3 @@ async fn ws_handler( reload_watcher.await.unwrap(); }) } - -#[cfg(feature = "hot_reload")] -async fn hot_reload_handler( - ws: WebSocketUpgrade, - _: Option>, - Extension(state): Extension>, -) -> impl IntoResponse { - ws.on_upgrade(|mut socket| async move { - log::info!("🔥 Hot Reload WebSocket connected"); - { - log::info!("Searching files for changes since last run..."); - // update any files that changed before the websocket connected. - let mut messages = Vec::new(); - - { - let handle = state.last_file_rebuild.lock().unwrap(); - let update_time = handle.last_updated_time.clone(); - for (k, v) in handle.map.iter() { - let mut file = File::open(k).unwrap(); - if let Ok(md) = file.metadata() { - if let Ok(time) = md.modified() { - if time < update_time { - continue; - } - } - } - let mut new = String::new(); - file.read_to_string(&mut new).expect("Unable to read file"); - if let Ok(new) = syn::parse_file(&new) { - if let Ok(old) = syn::parse_file(&v) { - if let DiffResult::RsxChanged(changed) = find_rsx(&new, &old) { - for (old, new) in changed.into_iter() { - if let Some(hr) = get_min_location( - k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), - old.to_token_stream(), - ) { - let rsx = new.to_string(); - let msg = SetRsxMessage { - location: hr, - new_text: rsx, - }; - messages.push(msg); - } - } - } - } - } - } - } - - for msg in &messages { - if socket - .send(Message::Text(serde_json::to_string(msg).unwrap())) - .await - .is_err() - { - return; - } - } - log::info!("Updated page"); - } - - let mut rx = state.messages.subscribe(); - let hot_reload_handle = tokio::spawn(async move { - loop { - let read_set_rsx = rx.recv(); - let read_err = socket.recv(); - tokio::select! { - err = read_err => { - if let Some(Ok(err)) = err { - if let Message::Text(err) = err { - let error: RecompileReason = serde_json::from_str(&err).unwrap(); - log::error!("{:?}", error); - if state.update.send("reload".to_string()).is_err() { - break; - } - } - } else { - break; - } - }, - set_rsx = read_set_rsx => { - if let Ok(rsx) = set_rsx { - if socket - .send(Message::Text(serde_json::to_string(&rsx).unwrap())) - .await - .is_err() - { - break; - }; - } - } - }; - } - }); - - hot_reload_handle.await.unwrap(); - }) -} - -#[cfg(feature = "hot_reload")] -fn get_min_location(path: &Path, ts: TokenStream) -> Option { - ts.into_iter() - .map(|tree| { - let location = tree.span(); - let start = location.start(); - CodeLocation { - file: path.display().to_string(), - line: start.line as u32, - column: start.column as u32 + 1, - } - }) - .min_by(|cl1, cl2| cl1.line.cmp(&cl2.line).then(cl1.column.cmp(&cl2.column))) -} From fb7ea5915b303fe79682a299bbb6bdc3907e2e82 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Jun 2022 09:47:16 -0500 Subject: [PATCH 140/895] use cli flag instead of feature flag --- Cargo.toml | 8 +++----- src/cli/cfg.rs | 5 +++++ src/cli/serve/mod.rs | 4 +++- src/config.rs | 8 ++++++++ src/lib.rs | 1 - src/server/mod.rs | 26 +++++++++++++++----------- 6 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 770fd7b1d..7f1223520 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,12 +46,10 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" -syn = { version = "1.0", optional = true } -dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter", optional = true } -proc-macro2 = { version = "1.0", features = ["span-locations"], optional = true } +syn = { version = "1.0" } +dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter" } +proc-macro2 = { version = "1.0", features = ["span-locations"] } -[features] -hot_reload = ["dioxus-rsx-interpreter", "proc-macro2", "syn"] [[bin]] path = "src/main.rs" diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index f5ee45b87..3f284cbbf 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -39,6 +39,11 @@ pub struct ConfigOptsServe { /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] pub platform: Option, + + /// Build with hot reloading rsx [default: false] + #[clap(long)] + #[serde(default)] + pub hot_reload: bool, } /// Ensure the given value for `--public-url` is formatted correctly. diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 85bd92c74..391e646d4 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -18,7 +18,9 @@ impl Serve { let mut crate_config = crate::CrateConfig::new()?; // change the relase state. - crate_config.with_release(self.serve.release); + crate_config + .with_release(self.serve.release) + .with_hot_reload(self.serve.hot_reload); if self.serve.example.is_some() { crate_config.as_example(self.serve.example.unwrap()); diff --git a/src/config.rs b/src/config.rs index 783c72ccd..aa2a03440 100644 --- a/src/config.rs +++ b/src/config.rs @@ -114,6 +114,7 @@ pub struct CrateConfig { pub executable: ExecutableType, pub dioxus_config: DioxusConfig, pub release: bool, + pub hot_reload: bool, } #[derive(Debug, Clone)] @@ -162,6 +163,7 @@ impl CrateConfig { let executable = ExecutableType::Binary(output_filename); let release = false; + let hot_reload = false; Ok(Self { out_dir, @@ -173,6 +175,7 @@ impl CrateConfig { executable, release, dioxus_config, + hot_reload, }) } @@ -186,6 +189,11 @@ impl CrateConfig { self } + pub fn with_hot_reload(&mut self, hot_reload: bool) -> &mut Self { + self.hot_reload = hot_reload; + self + } + // pub fn with_build_options(&mut self, options: &BuildOptions) { // if let Some(name) = &options.example { // self.as_example(name.clone()); diff --git a/src/lib.rs b/src/lib.rs index 683b7251a..6d009c18c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,5 +19,4 @@ pub use error::*; pub mod logging; pub use logging::*; -#[cfg(feature = "hot_reload")] pub mod hot_reload; diff --git a/src/server/mod.rs b/src/server/mod.rs index 262dbf17d..8a98fd9d9 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -15,20 +15,24 @@ use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; use crate::{builder, serve::Serve, CrateConfig, Result}; use tokio::sync::broadcast; -#[cfg(feature = "hot_reload")] mod hot_reload; -#[cfg(feature = "hot_reload")] use hot_reload::*; struct WsReloadState { update: broadcast::Sender, - #[cfg(feature = "hot_reload")] - last_file_rebuild: Arc>, + last_file_rebuild: Option>>, watcher_config: CrateConfig, } -#[cfg(feature = "hot_reload")] pub async fn startup(config: CrateConfig) -> Result<()> { + if config.hot_reload { + startup_hot_reload(config).await + } else { + startup_default(config).await + } +} + +pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -46,7 +50,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), - last_file_rebuild: last_file_rebuild.clone(), + last_file_rebuild: Some(last_file_rebuild.clone()), watcher_config: config.clone(), }); @@ -186,8 +190,7 @@ pub async fn startup(config: CrateConfig) -> Result<()> { Ok(()) } -#[cfg(not(feature = "hot_reload"))] -pub async fn startup(config: CrateConfig) -> Result<()> { +pub async fn startup_default(config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -196,6 +199,8 @@ pub async fn startup(config: CrateConfig) -> Result<()> { let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), + + last_file_rebuild: None, watcher_config: config.clone(), }); @@ -313,9 +318,8 @@ async fn ws_handler( { let _ = Serve::regen_dev_page(&state.watcher_config); } - #[cfg(feature = "hot_reload")] - { - let mut write = state.last_file_rebuild.lock().unwrap(); + if let Some(file_map) = &state.last_file_rebuild { + let mut write = file_map.lock().unwrap(); *write = FileMap::new(state.watcher_config.crate_dir.clone()); } } From b0f987aa106994e95af8e75765ce12321684821b Mon Sep 17 00:00:00 2001 From: Demonthos <66571940+Demonthos@users.noreply.github.com> Date: Wed, 15 Jun 2022 12:55:25 -0500 Subject: [PATCH 141/895] accept all interperter errors --- src/server/hot_reload.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 661d249e6..a9f51abe7 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -7,7 +7,7 @@ use std::{path::PathBuf, sync::Arc}; pub use crate::hot_reload::{find_rsx, DiffResult}; use crate::CrateConfig; -pub use dioxus_rsx_interpreter::{error::RecompileReason, CodeLocation, SetRsxMessage}; +pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetRsxMessage}; pub use proc_macro2::TokenStream; pub use std::collections::HashMap; pub use std::sync::Mutex; @@ -130,7 +130,7 @@ pub async fn hot_reload_handler( err = read_err => { if let Some(Ok(err)) = err { if let Message::Text(err) = err { - let error: RecompileReason = serde_json::from_str(&err).unwrap(); + let error: Error = serde_json::from_str(&err).unwrap(); log::error!("{:?}", error); if state.update.send("reload".to_string()).is_err() { break; From 8ff50df3a5dc14b90b15fd84122a12436326144a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 15 Jun 2022 13:29:35 -0500 Subject: [PATCH 142/895] preserve whitespace in rsx --- src/server/hot_reload.rs | 37 ++++++++++++++++--------------------- src/server/mod.rs | 29 ++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index a9f51abe7..f79a7a50e 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -15,6 +15,7 @@ pub use std::time::SystemTime; pub use std::{fs, io, path::Path}; pub use std::{fs::File, io::Read}; pub use syn::__private::ToTokens; +use syn::spanned::Spanned; use tokio::sync::broadcast; pub struct HotReloadState { @@ -91,17 +92,16 @@ pub async fn hot_reload_handler( if let Ok(old) = syn::parse_file(&v) { if let DiffResult::RsxChanged(changed) = find_rsx(&new, &old) { for (old, new) in changed.into_iter() { - if let Some(hr) = get_min_location( + let hr = get_location( k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), old.to_token_stream(), - ) { - let rsx = new.to_string(); - let msg = SetRsxMessage { - location: hr, - new_text: rsx, - }; - messages.push(msg); - } + ); + let rsx = new.to_string(); + let msg = SetRsxMessage { + location: hr, + new_text: rsx, + }; + messages.push(msg); } } } @@ -159,16 +159,11 @@ pub async fn hot_reload_handler( }) } -pub fn get_min_location(path: &Path, ts: TokenStream) -> Option { - ts.into_iter() - .map(|tree| { - let location = tree.span(); - let start = location.start(); - CodeLocation { - file: path.display().to_string(), - line: start.line as u32, - column: start.column as u32 + 1, - } - }) - .min_by(|cl1, cl2| cl1.line.cmp(&cl2.line).then(cl1.column.cmp(&cl2.column))) +pub fn get_location(path: &Path, ts: TokenStream) -> CodeLocation { + let span = ts.span().start(); + CodeLocation { + file: path.display().to_string(), + line: span.line as u32, + column: span.column as u32 + 1, + } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 8a98fd9d9..3397beac6 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,6 +7,7 @@ use axum::{ Router, }; use notify::{RecommendedWatcher, Watcher}; +use syn::spanned::Spanned; use std::{path::PathBuf, sync::Arc}; use tower::ServiceBuilder; @@ -93,16 +94,30 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { DiffResult::RsxChanged(changed) => { log::info!("reloading rsx"); for (old, new) in changed.into_iter() { - if let Some(hr) = get_min_location( + let hr = get_location( &path.strip_prefix(&crate_dir).unwrap().to_path_buf(), old.to_token_stream(), - ) { - let rsx = new.to_string(); - let _ = hot_reload_tx.send(SetRsxMessage { - location: hr, - new_text: rsx, - }); + ); + // get the original source code to preserve whitespace + let span = new.span(); + let start = span.start(); + let end = span.end(); + let mut lines: Vec<_> = src + .lines() + .skip(start.line - 1) + .take(end.line - start.line + 1) + .collect(); + if let Some(first) = lines.first_mut() { + *first = first.split_at(start.column).1; } + if let Some(last) = lines.last_mut() { + *last = last.split_at(end.column).0; + } + let rsx = lines.join("\n"); + let _ = hot_reload_tx.send(SetRsxMessage { + location: hr, + new_text: rsx, + }); } } } From edc31dfc031025a6a7893da39fe3278fa053d2c7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 15 Jun 2022 13:58:24 -0500 Subject: [PATCH 143/895] better error messages --- src/server/hot_reload.rs | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index f79a7a50e..2011b8958 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -86,22 +86,36 @@ pub async fn hot_reload_handler( } } } - let mut new = String::new(); - file.read_to_string(&mut new).expect("Unable to read file"); - if let Ok(new) = syn::parse_file(&new) { - if let Ok(old) = syn::parse_file(&v) { - if let DiffResult::RsxChanged(changed) = find_rsx(&new, &old) { + let mut new_str = String::new(); + file.read_to_string(&mut new_str).expect("Unable to read file"); + if let Ok(new_file) = syn::parse_file(&new_str) { + if let Ok(old_file) = syn::parse_file(&v) { + if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file) { for (old, new) in changed.into_iter() { let hr = get_location( k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), old.to_token_stream(), ); - let rsx = new.to_string(); - let msg = SetRsxMessage { + // get the original source code to preserve whitespace + let span = new.span(); + let start = span.start(); + let end = span.end(); + let mut lines: Vec<_> = new_str + .lines() + .skip(start.line - 1) + .take(end.line - start.line + 1) + .collect(); + if let Some(first) = lines.first_mut() { + *first = first.split_at(start.column).1; + } + if let Some(last) = lines.last_mut() { + *last = last.split_at(end.column).0; + } + let rsx = lines.join("\n"); + messages.push(SetRsxMessage { location: hr, new_text: rsx, - }; - messages.push(msg); + }); } } } @@ -131,9 +145,16 @@ pub async fn hot_reload_handler( if let Some(Ok(err)) = err { if let Message::Text(err) = err { let error: Error = serde_json::from_str(&err).unwrap(); - log::error!("{:?}", error); - if state.update.send("reload".to_string()).is_err() { - break; + match error{ + Error::ParseError(parse_error) => { + log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file, parse_error.location.line, parse_error.location.column, parse_error.message); + }, + Error::RecompileRequiredError(reason) => { + log::info!("{:?}", reason); + if state.update.send("reload".to_string()).is_err() { + break; + } + } } } } else { From 8e33b8e02711cc4108f4d05d2cf95d647ad697d7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 16 Jun 2022 09:11:02 -0500 Subject: [PATCH 144/895] improve speed when reloading the site --- src/server/hot_reload.rs | 91 +++++++++++++++++++++-------- src/server/mod.rs | 120 +++++++++++++++++++++------------------ 2 files changed, 132 insertions(+), 79 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 2011b8958..14f9ffbc6 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -2,12 +2,13 @@ use axum::{ extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, response::IntoResponse, }; +use dioxus_rsx_interpreter::SetRsxMessage; use std::{path::PathBuf, sync::Arc}; pub use crate::hot_reload::{find_rsx, DiffResult}; use crate::CrateConfig; -pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetRsxMessage}; +pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetManyRsxMessage}; pub use proc_macro2::TokenStream; pub use std::collections::HashMap; pub use std::sync::Mutex; @@ -19,7 +20,7 @@ use syn::spanned::Spanned; use tokio::sync::broadcast; pub struct HotReloadState { - pub messages: broadcast::Sender, + pub messages: broadcast::Sender, pub update: broadcast::Sender, pub last_file_rebuild: Arc>, pub watcher_config: CrateConfig, @@ -32,32 +33,76 @@ pub struct FileMap { impl FileMap { pub fn new(path: PathBuf) -> Self { + log::info!("Searching files for changes since last compile..."); fn find_rs_files(root: PathBuf) -> io::Result> { let mut files = HashMap::new(); if root.is_dir() { - let mut handles = Vec::new(); for entry in fs::read_dir(root)? { if let Ok(entry) = entry { let path = entry.path(); - handles.push(std::thread::spawn(move || find_rs_files(path))); + files.extend(find_rs_files(path)?); } } - for handle in handles { - files.extend(handle.join().unwrap()?); - } } else { if root.extension().map(|s| s.to_str()).flatten() == Some("rs") { - let mut file = File::open(root.clone()).unwrap(); - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - files.insert(root, src); + if let Ok(mut file) = File::open(root.clone()) { + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + files.insert(root, src); + } } } Ok(files) } - Self { - last_updated_time: SystemTime::now(), + + let last_updated_time = SystemTime::now(); + let result = Self { + last_updated_time, map: find_rs_files(path).unwrap(), + }; + log::info!("Files updated"); + result + } + + pub fn update(&mut self, path: PathBuf) { + log::info!("Updating files that changed since last compile..."); + self.last_updated_time = SystemTime::now(); + self.update_inner(path); + log::info!("Files updated"); + } + + fn update_inner(&mut self, path: PathBuf) { + if path.is_dir() { + if let Ok(files) = fs::read_dir(path) { + for entry in files { + if let Ok(entry) = entry { + if let Ok(md) = entry.metadata() { + if let Ok(time) = md.modified() { + if time < self.last_updated_time { + return; + } + } + } + let path = entry.path(); + self.update(path); + } + } + } + } else { + if path.extension().map(|s| s.to_str()).flatten() == Some("rs") { + if let Ok(mut file) = File::open(path.clone()) { + if let Ok(md) = file.metadata() { + if let Ok(time) = md.modified() { + if time < self.last_updated_time { + return; + } + } + } + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + self.map.insert(path, src); + } + } } } } @@ -70,7 +115,6 @@ pub async fn hot_reload_handler( ws.on_upgrade(|mut socket| async move { log::info!("🔥 Hot Reload WebSocket connected"); { - log::info!("Searching files for changes since last run..."); // update any files that changed before the websocket connected. let mut messages = Vec::new(); @@ -123,16 +167,14 @@ pub async fn hot_reload_handler( } } - for msg in &messages { - if socket - .send(Message::Text(serde_json::to_string(msg).unwrap())) - .await - .is_err() - { - return; - } + let msg = SetManyRsxMessage(messages); + if socket + .send(Message::Text(serde_json::to_string(&msg).unwrap())) + .await + .is_err() + { + return; } - log::info!("Updated page"); } let mut rx = state.messages.subscribe(); @@ -149,8 +191,7 @@ pub async fn hot_reload_handler( Error::ParseError(parse_error) => { log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file, parse_error.location.line, parse_error.location.column, parse_error.message); }, - Error::RecompileRequiredError(reason) => { - log::info!("{:?}", reason); + Error::RecompileRequiredError(_) => { if state.update.send("reload".to_string()).is_err() { break; } diff --git a/src/server/mod.rs b/src/server/mod.rs index 3397beac6..19791fd79 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,6 +6,7 @@ use axum::{ routing::{get, get_service}, Router, }; +use dioxus_rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; use syn::spanned::Spanned; @@ -67,67 +68,75 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { .unwrap_or_else(|| vec![PathBuf::from("src")]); let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { - if let Ok(evt) = evt { - for path in evt.paths { - let mut file = File::open(path.clone()).unwrap(); - if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { - continue; - } - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - if src.is_empty() { - continue; - } - // find changes to the rsx in the file - if let Ok(syntax) = syn::parse_file(&src) { - let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); - if let Some(old_str) = last_file_rebuild.map.get(&path) { - if let Ok(old) = syn::parse_file(&old_str) { - match find_rsx(&syntax, &old) { - DiffResult::CodeChanged => { - log::info!("reload required"); - if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); + if chrono::Local::now().timestamp() > last_update_time { + if let Ok(evt) = evt { + let mut messages = Vec::new(); + for path in evt.paths { + let mut file = File::open(path.clone()).unwrap(); + if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { + continue; + } + let mut src = String::new(); + file.read_to_string(&mut src).expect("Unable to read file"); + if src.is_empty() { + continue; + } + // find changes to the rsx in the file + if let Ok(syntax) = syn::parse_file(&src) { + let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); + if let Some(old_str) = last_file_rebuild.map.get(&path) { + if let Ok(old) = syn::parse_file(&old_str) { + match find_rsx(&syntax, &old) { + DiffResult::CodeChanged => { + log::info!("reload required"); + let _ = reload_tx.send("reload time".into()); + break; } - } - DiffResult::RsxChanged(changed) => { - log::info!("reloading rsx"); - for (old, new) in changed.into_iter() { - let hr = get_location( - &path.strip_prefix(&crate_dir).unwrap().to_path_buf(), - old.to_token_stream(), - ); - // get the original source code to preserve whitespace - let span = new.span(); - let start = span.start(); - let end = span.end(); - let mut lines: Vec<_> = src - .lines() - .skip(start.line - 1) - .take(end.line - start.line + 1) - .collect(); - if let Some(first) = lines.first_mut() { - *first = first.split_at(start.column).1; + DiffResult::RsxChanged(changed) => { + log::info!("reloading rsx"); + for (old, new) in changed.into_iter() { + let hr = get_location( + &path + .strip_prefix(&crate_dir) + .unwrap() + .to_path_buf(), + old.to_token_stream(), + ); + // get the original source code to preserve whitespace + let span = new.span(); + let start = span.start(); + let end = span.end(); + let mut lines: Vec<_> = src + .lines() + .skip(start.line - 1) + .take(end.line - start.line + 1) + .collect(); + if let Some(first) = lines.first_mut() { + *first = first.split_at(start.column).1; + } + if let Some(last) = lines.last_mut() { + *last = last.split_at(end.column).0; + } + let rsx = lines.join("\n"); + messages.push(SetRsxMessage { + location: hr, + new_text: rsx, + }); } - if let Some(last) = lines.last_mut() { - *last = last.split_at(end.column).0; - } - let rsx = lines.join("\n"); - let _ = hot_reload_tx.send(SetRsxMessage { - location: hr, - new_text: rsx, - }); } } } + } else { + // if this is a new file, rebuild the project + *last_file_rebuild = FileMap::new(crate_dir.clone()); } - } else { - // if this is a new file, rebuild the project - *last_file_rebuild = FileMap::new(crate_dir.clone()); } } + if !messages.is_empty() { + let _ = hot_reload_tx.send(SetManyRsxMessage(messages)); + } } + last_update_time = chrono::Local::now().timestamp(); } }) .unwrap(); @@ -313,7 +322,7 @@ async fn ws_handler( _: Option>, Extension(state): Extension>, ) -> impl IntoResponse { - ws.on_upgrade(|mut socket| async move { + ws.max_send_queue(1).on_upgrade(|mut socket| async move { let mut rx = state.update.subscribe(); let reload_watcher = tokio::spawn(async move { loop { @@ -335,7 +344,7 @@ async fn ws_handler( } if let Some(file_map) = &state.last_file_rebuild { let mut write = file_map.lock().unwrap(); - *write = FileMap::new(state.watcher_config.crate_dir.clone()); + write.update(state.watcher_config.crate_dir.clone()); } } // ignore the error @@ -346,6 +355,9 @@ async fn ws_handler( { break; } + + // flush the errors after recompling + rx = rx.resubscribe(); } } }); From 22e40c6bc1f35f0a3c9a6ec9d225f7c4fe029fff Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 16 Jun 2022 10:21:28 -0500 Subject: [PATCH 145/895] removed debugging messages --- src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 19791fd79..bf9299022 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -89,7 +89,7 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { match find_rsx(&syntax, &old) { DiffResult::CodeChanged => { log::info!("reload required"); - let _ = reload_tx.send("reload time".into()); + let _ = reload_tx.send("reload".into()); break; } DiffResult::RsxChanged(changed) => { From a79046f36a39a20cc4e43f8e3d83df46e23b4fa5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 16 Jun 2022 13:13:06 -0500 Subject: [PATCH 146/895] use build manager instead of rebuilding in the ws handler --- src/server/hot_reload.rs | 53 +++--------------- src/server/mod.rs | 115 ++++++++++++++++++++++----------------- 2 files changed, 72 insertions(+), 96 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 14f9ffbc6..6a2a58ba0 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -6,6 +6,7 @@ use dioxus_rsx_interpreter::SetRsxMessage; use std::{path::PathBuf, sync::Arc}; +use super::BuildManager; pub use crate::hot_reload::{find_rsx, DiffResult}; use crate::CrateConfig; pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetManyRsxMessage}; @@ -21,7 +22,7 @@ use tokio::sync::broadcast; pub struct HotReloadState { pub messages: broadcast::Sender, - pub update: broadcast::Sender, + pub build_manager: Arc, pub last_file_rebuild: Arc>, pub watcher_config: CrateConfig, } @@ -63,48 +64,6 @@ impl FileMap { log::info!("Files updated"); result } - - pub fn update(&mut self, path: PathBuf) { - log::info!("Updating files that changed since last compile..."); - self.last_updated_time = SystemTime::now(); - self.update_inner(path); - log::info!("Files updated"); - } - - fn update_inner(&mut self, path: PathBuf) { - if path.is_dir() { - if let Ok(files) = fs::read_dir(path) { - for entry in files { - if let Ok(entry) = entry { - if let Ok(md) = entry.metadata() { - if let Ok(time) = md.modified() { - if time < self.last_updated_time { - return; - } - } - } - let path = entry.path(); - self.update(path); - } - } - } - } else { - if path.extension().map(|s| s.to_str()).flatten() == Some("rs") { - if let Ok(mut file) = File::open(path.clone()) { - if let Ok(md) = file.metadata() { - if let Ok(time) = md.modified() { - if time < self.last_updated_time { - return; - } - } - } - let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); - self.map.insert(path, src); - } - } - } - } } pub async fn hot_reload_handler( @@ -115,10 +74,11 @@ pub async fn hot_reload_handler( ws.on_upgrade(|mut socket| async move { log::info!("🔥 Hot Reload WebSocket connected"); { - // update any files that changed before the websocket connected. + // update any rsx calls that changed before the websocket connected. let mut messages = Vec::new(); { + println!("Finding updates since last reload..."); let handle = state.last_file_rebuild.lock().unwrap(); let update_time = handle.last_updated_time.clone(); for (k, v) in handle.map.iter() { @@ -165,6 +125,7 @@ pub async fn hot_reload_handler( } } } + println!("finished"); } let msg = SetManyRsxMessage(messages); @@ -192,8 +153,8 @@ pub async fn hot_reload_handler( log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file, parse_error.location.line, parse_error.location.column, parse_error.message); }, Error::RecompileRequiredError(_) => { - if state.update.send("reload".to_string()).is_err() { - break; + if let Err(err) = state.build_manager.build(){ + log::error!("{}", err); } } } diff --git a/src/server/mod.rs b/src/server/mod.rs index bf9299022..5742c86ee 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -20,18 +20,43 @@ use tokio::sync::broadcast; mod hot_reload; use hot_reload::*; +pub struct BuildManager { + config: CrateConfig, + reload_tx: broadcast::Sender<()>, +} + +impl BuildManager { + fn build(&self) -> Result<()> { + log::info!("Start to rebuild project..."); + builder::build(&self.config)?; + // change the websocket reload state to true; + // the page will auto-reload. + if self + .config + .dioxus_config + .web + .watcher + .reload_html + .unwrap_or(false) + { + let _ = Serve::regen_dev_page(&self.config); + } + let _ = self.reload_tx.send(()); + Ok(()) + } +} + struct WsReloadState { - update: broadcast::Sender, - last_file_rebuild: Option>>, - watcher_config: CrateConfig, + update: broadcast::Sender<()>, } pub async fn startup(config: CrateConfig) -> Result<()> { if config.hot_reload { - startup_hot_reload(config).await + startup_hot_reload(config).await? } else { - startup_default(config).await + startup_default(config).await? } + Ok(()) } pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { @@ -40,10 +65,14 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { let dist_path = config.out_dir.clone(); let (reload_tx, _) = broadcast::channel(100); let last_file_rebuild = Arc::new(Mutex::new(FileMap::new(config.crate_dir.clone()))); + let build_manager = Arc::new(BuildManager { + config: config.clone(), + reload_tx: reload_tx.clone(), + }); let hot_reload_tx = broadcast::channel(100).0; let hot_reload_state = Arc::new(HotReloadState { messages: hot_reload_tx.clone(), - update: reload_tx.clone(), + build_manager: build_manager.clone(), last_file_rebuild: last_file_rebuild.clone(), watcher_config: config.clone(), }); @@ -51,9 +80,6 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { let crate_dir = config.crate_dir.clone(); let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), - - last_file_rebuild: Some(last_file_rebuild.clone()), - watcher_config: config.clone(), }); let mut last_update_time = chrono::Local::now().timestamp(); @@ -71,6 +97,7 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { if chrono::Local::now().timestamp() > last_update_time { if let Ok(evt) = evt { let mut messages = Vec::new(); + let mut needs_rebuild = false; for path in evt.paths { let mut file = File::open(path.clone()).unwrap(); if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { @@ -88,9 +115,8 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { if let Ok(old) = syn::parse_file(&old_str) { match find_rsx(&syntax, &old) { DiffResult::CodeChanged => { - log::info!("reload required"); - let _ = reload_tx.send("reload".into()); - break; + needs_rebuild = true; + last_file_rebuild.map.insert(path, src); } DiffResult::RsxChanged(changed) => { log::info!("reloading rsx"); @@ -132,6 +158,12 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { } } } + if needs_rebuild { + log::info!("reload required"); + if let Err(err) = build_manager.build() { + log::error!("{}", err); + } + } if !messages.is_empty() { let _ = hot_reload_tx.send(SetManyRsxMessage(messages)); } @@ -221,11 +253,13 @@ pub async fn startup_default(config: CrateConfig) -> Result<()> { let (reload_tx, _) = broadcast::channel(100); + let build_manager = BuildManager { + config: config.clone(), + reload_tx: reload_tx.clone(), + }; + let ws_reload_state = Arc::new(WsReloadState { update: reload_tx.clone(), - - last_file_rebuild: None, - watcher_config: config.clone(), }); let mut last_update_time = chrono::Local::now().timestamp(); @@ -242,8 +276,10 @@ pub async fn startup_default(config: CrateConfig) -> Result<()> { let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { log::info!("reload required"); if chrono::Local::now().timestamp() > last_update_time { - let _ = reload_tx.send("reload".into()); - last_update_time = chrono::Local::now().timestamp(); + match build_manager.build() { + Ok(_) => last_update_time = chrono::Local::now().timestamp(), + Err(e) => log::error!("{}", e), + } } }) .unwrap(); @@ -322,43 +358,22 @@ async fn ws_handler( _: Option>, Extension(state): Extension>, ) -> impl IntoResponse { - ws.max_send_queue(1).on_upgrade(|mut socket| async move { + ws.on_upgrade(|mut socket| async move { let mut rx = state.update.subscribe(); let reload_watcher = tokio::spawn(async move { loop { - let v = rx.recv().await.unwrap(); - if v == "reload" { - log::info!("Start to rebuild project..."); - if builder::build(&state.watcher_config).is_ok() { - // change the websocket reload state to true; - // the page will auto-reload. - if state - .watcher_config - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { - let _ = Serve::regen_dev_page(&state.watcher_config); - } - if let Some(file_map) = &state.last_file_rebuild { - let mut write = file_map.lock().unwrap(); - write.update(state.watcher_config.crate_dir.clone()); - } - } - // ignore the error - if socket - .send(Message::Text(String::from("reload"))) - .await - .is_err() - { - break; - } - - // flush the errors after recompling - rx = rx.resubscribe(); + rx.recv().await.unwrap(); + // ignore the error + if socket + .send(Message::Text(String::from("reload"))) + .await + .is_err() + { + break; } + + // flush the errors after recompling + rx = rx.resubscribe(); } }); From 815bdcdf0032a37518ee1611d9b0cd08bd2c79f3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 16 Jun 2022 13:23:45 -0500 Subject: [PATCH 147/895] clean up logs --- src/server/hot_reload.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 6a2a58ba0..a0eb43e08 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -78,7 +78,7 @@ pub async fn hot_reload_handler( let mut messages = Vec::new(); { - println!("Finding updates since last reload..."); + log::info!("Finding updates since last compile..."); let handle = state.last_file_rebuild.lock().unwrap(); let update_time = handle.last_updated_time.clone(); for (k, v) in handle.map.iter() { @@ -125,7 +125,7 @@ pub async fn hot_reload_handler( } } } - println!("finished"); + log::info!("finished"); } let msg = SetManyRsxMessage(messages); From 2908e53d1b55d6d5664d1b27046d53966d42bd5e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 17 Jun 2022 14:50:05 -0500 Subject: [PATCH 148/895] add delay before reading the changed file --- src/server/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 1eb159ae5..16401aa85 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -95,6 +95,8 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { if chrono::Local::now().timestamp() > last_update_time { + // Give time for the change to take effect before reading the file + std::thread::sleep(std::time::Duration::from_millis(100)); if let Ok(evt) = evt { let mut messages = Vec::new(); let mut needs_rebuild = false; @@ -105,9 +107,6 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { } let mut src = String::new(); file.read_to_string(&mut src).expect("Unable to read file"); - if src.is_empty() { - continue; - } // find changes to the rsx in the file if let Ok(syntax) = syn::parse_file(&src) { let mut last_file_rebuild = last_file_rebuild.lock().unwrap(); From 7025bd43aab4e98c8fe1b5907f51c19117efc814 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 20 Jun 2022 15:44:14 -0500 Subject: [PATCH 149/895] use line!, col!, and row! instead of panic location --- src/server/hot_reload.rs | 2 +- src/server/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index a0eb43e08..7c9a6957e 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -97,7 +97,7 @@ pub async fn hot_reload_handler( if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file) { for (old, new) in changed.into_iter() { let hr = get_location( - k.strip_prefix(&state.watcher_config.crate_dir).unwrap(), + k, old.to_token_stream(), ); // get the original source code to preserve whitespace diff --git a/src/server/mod.rs b/src/server/mod.rs index 16401aa85..8cdd76373 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -121,10 +121,7 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { log::info!("reloading rsx"); for (old, new) in changed.into_iter() { let hr = get_location( - &path - .strip_prefix(&crate_dir) - .unwrap() - .to_path_buf(), + &path.to_path_buf(), old.to_token_stream(), ); // get the original source code to preserve whitespace From f8014f307b7ae0ac53a9415e4849d35b4a286fc3 Mon Sep 17 00:00:00 2001 From: Demonthos <66571940+Demonthos@users.noreply.github.com> Date: Tue, 21 Jun 2022 10:19:42 -0500 Subject: [PATCH 150/895] depend on dioxus master until next release --- Cargo.toml | 2 +- src/server/hot_reload.rs | 4 ++-- src/server/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5afe80db..59a840d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ zip = "0.6.2" tower = "0.4.12" syn = { version = "1.0" } -dioxus-rsx-interpreter = { path = "../dioxus/packages/rsx_interpreter" } +dioxus = { git = "https://github.com/dioxuslabs/dioxus/", features = ["hot_reload"] } proc-macro2 = { version = "1.0", features = ["span-locations"] } diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 7c9a6957e..ea9c64fc7 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -2,14 +2,14 @@ use axum::{ extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, response::IntoResponse, }; -use dioxus_rsx_interpreter::SetRsxMessage; +use dioxus::rsx_interpreter::SetRsxMessage; use std::{path::PathBuf, sync::Arc}; use super::BuildManager; pub use crate::hot_reload::{find_rsx, DiffResult}; use crate::CrateConfig; -pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetManyRsxMessage}; +pub use dioxus::rsx_interpreter::{error::Error, CodeLocation, SetManyRsxMessage}; pub use proc_macro2::TokenStream; pub use std::collections::HashMap; pub use std::sync::Mutex; diff --git a/src/server/mod.rs b/src/server/mod.rs index 8cdd76373..387355ee9 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,7 +6,7 @@ use axum::{ routing::{get, get_service}, Router, }; -use dioxus_rsx_interpreter::SetRsxMessage; +use dioxus::rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; use syn::spanned::Spanned; From abded864c315400c1b7b0b1f80af9bf182a2b9c1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 28 Jun 2022 09:59:05 -0500 Subject: [PATCH 151/895] update hot_reload to hot-reload --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 59a840d77..42de2ba4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ zip = "0.6.2" tower = "0.4.12" syn = { version = "1.0" } -dioxus = { git = "https://github.com/dioxuslabs/dioxus/", features = ["hot_reload"] } +dioxus = { git = "https://github.com/dioxuslabs/dioxus/", features = ["hot-reload"] } proc-macro2 = { version = "1.0", features = ["span-locations"] } From c9ac828ec773ad37f5fa5c12cfc610e9506d6ab8 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 28 Jun 2022 10:00:02 -0500 Subject: [PATCH 152/895] fix path seperator --- src/server/hot_reload.rs | 9 ++++++--- src/server/mod.rs | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index ea9c64fc7..d34f079f5 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -97,6 +97,7 @@ pub async fn hot_reload_handler( if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file) { for (old, new) in changed.into_iter() { let hr = get_location( + &state.watcher_config.crate_dir, k, old.to_token_stream(), ); @@ -150,7 +151,7 @@ pub async fn hot_reload_handler( let error: Error = serde_json::from_str(&err).unwrap(); match error{ Error::ParseError(parse_error) => { - log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file, parse_error.location.line, parse_error.location.column, parse_error.message); + log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file_path, parse_error.location.line, parse_error.location.column, parse_error.message); }, Error::RecompileRequiredError(_) => { if let Err(err) = state.build_manager.build(){ @@ -182,10 +183,12 @@ pub async fn hot_reload_handler( }) } -pub fn get_location(path: &Path, ts: TokenStream) -> CodeLocation { +pub fn get_location(crate_path: &Path, path: &Path, ts: TokenStream) -> CodeLocation { let span = ts.span().start(); + let relative = path.strip_prefix(crate_path).unwrap(); CodeLocation { - file: path.display().to_string(), + file_path: relative.display().to_string(), + crate_path: crate_path.display().to_string(), line: span.line as u32, column: span.column as u32 + 1, } diff --git a/src/server/mod.rs b/src/server/mod.rs index 387355ee9..4bb08170e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -121,6 +121,7 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { log::info!("reloading rsx"); for (old, new) in changed.into_iter() { let hr = get_location( + &crate_dir, &path.to_path_buf(), old.to_token_stream(), ); From c54d4677302a6bafcd9185fd3340fb59f94c6047 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 29 Jun 2022 16:40:23 +0800 Subject: [PATCH 153/895] feat: set `port` configurable --- src/cli/cfg.rs | 5 +++++ src/cli/serve/mod.rs | 2 +- src/server/mod.rs | 14 ++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 73f9570d4..9fe453c49 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -40,6 +40,11 @@ pub struct ConfigOptsServe { #[clap(parse(from_os_str))] pub target: Option, + /// Port of dev server + #[clap(long)] + #[clap(default_value_t = 8080)] + pub port: u16, + /// Build a example [default: ""] #[clap(long)] pub example: Option, diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 5511845cb..5528ebade 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -69,7 +69,7 @@ impl Serve { Serve::regen_dev_page(&crate_config)?; // start the develop server - server::startup(crate_config.clone()).await?; + server::startup(self.serve.port, crate_config.clone()).await?; Ok(()) } diff --git a/src/server/mod.rs b/src/server/mod.rs index 387355ee9..096b07cc0 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -50,16 +50,16 @@ struct WsReloadState { update: broadcast::Sender<()>, } -pub async fn startup(config: CrateConfig) -> Result<()> { +pub async fn startup(port: u16, config: CrateConfig) -> Result<()> { if config.hot_reload { - startup_hot_reload(config).await? + startup_hot_reload(port, config).await? } else { - startup_default(config).await? + startup_default(port, config).await? } Ok(()) } -pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { +pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -179,7 +179,6 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0:8080 - let port = "8080"; log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); let file_service_config = config.clone(); @@ -242,7 +241,7 @@ pub async fn startup_hot_reload(config: CrateConfig) -> Result<()> { Ok(()) } -pub async fn startup_default(config: CrateConfig) -> Result<()> { +pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -289,8 +288,7 @@ pub async fn startup_default(config: CrateConfig) -> Result<()> { .unwrap(); } - // start serve dev-server at 0.0.0.0:8080 - let port = "8080"; + // start serve dev-server at 0.0.0.0 log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); let file_service_config = config.clone(); From f4ed207649e8dbcb36092f5db58834edded7c0de Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 00:22:40 +0800 Subject: [PATCH 154/895] feat: commit code --- src/server/hot_reload.rs | 6 +++--- src/server/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index ea9c64fc7..6f494dfc7 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -34,7 +34,7 @@ pub struct FileMap { impl FileMap { pub fn new(path: PathBuf) -> Self { - log::info!("Searching files for changes since last compile..."); + log::info!("🔮 Searching files for changes since last compile..."); fn find_rs_files(root: PathBuf) -> io::Result> { let mut files = HashMap::new(); if root.is_dir() { @@ -61,7 +61,7 @@ impl FileMap { last_updated_time, map: find_rs_files(path).unwrap(), }; - log::info!("Files updated"); + // log::info!("Files updated"); result } } @@ -78,7 +78,7 @@ pub async fn hot_reload_handler( let mut messages = Vec::new(); { - log::info!("Finding updates since last compile..."); + log::info!("🔮 Finding updates since last compile..."); let handle = state.last_file_rebuild.lock().unwrap(); let update_time = handle.last_updated_time.clone(); for (k, v) in handle.map.iter() { diff --git a/src/server/mod.rs b/src/server/mod.rs index 096b07cc0..75134a1ac 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -27,7 +27,7 @@ pub struct BuildManager { impl BuildManager { fn build(&self) -> Result<()> { - log::info!("Start to rebuild project..."); + log::info!("🪁 Rebuild code"); builder::build(&self.config)?; // change the websocket reload state to true; // the page will auto-reload. @@ -118,7 +118,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { last_file_rebuild.map.insert(path, src); } DiffResult::RsxChanged(changed) => { - log::info!("reloading rsx"); + log::info!("🪁 reloading rsx"); for (old, new) in changed.into_iter() { let hr = get_location( &path.to_path_buf(), @@ -269,7 +269,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { .unwrap_or_else(|| vec![PathBuf::from("src")]); let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { - log::info!("reload required"); + // log::info!("🚧 reload required"); if chrono::Local::now().timestamp() > last_update_time { match build_manager.build() { Ok(_) => last_update_time = chrono::Local::now().timestamp(), From baab2b9b4f56f120735fd602d2cf923a6988e2f7 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 6 Jul 2022 00:45:22 -0400 Subject: [PATCH 155/895] feat: use local bundle strategy --- .gitignore | 3 +- Cargo.toml | 6 +- build.rs | 50 + extension/dist/.gitignore | 2 + extension/package-lock.json | 4436 +++++++++++++++++++++++++---------- extension/package.json | 42 +- extension/server/.gitignore | 3 + extension/src/extension.ts | 139 -- extension/src/main.ts | 184 ++ src/cli/autoformat/mod.rs | 4 +- src/cli/mod.rs | 5 + src/cli/version.rs | 76 + src/main.rs | 5 + 13 files changed, 3604 insertions(+), 1351 deletions(-) create mode 100644 build.rs create mode 100644 extension/dist/.gitignore create mode 100644 extension/server/.gitignore delete mode 100644 extension/src/extension.ts create mode 100644 extension/src/main.ts create mode 100644 src/cli/version.rs diff --git a/.gitignore b/.gitignore index 2e049011e..5d6f4db1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Cargo.lock -.idea/ \ No newline at end of file +.idea/ +.DS_Store diff --git a/Cargo.toml b/Cargo.toml index 9f85a89c2..506f14543 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,10 +46,8 @@ flate2 = "1.0.22" tar = "0.4.38" tower = "0.4.12" -dioxus-rsx = { path = "../../dioxus/packages/rsx" } -dioxus-autofmt = { path = "../../dioxus/packages/autofmt" } -# dioxus-rsx = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } -# dioxus-autofmt = { git = "https://github.com/dioxuslabs/dioxus.git", branch = "jk/rsx-refactor" } +dioxus-rsx = { git = "https://github.com/dioxuslabs/dioxus.git" } +dioxus-autofmt = { git = "https://github.com/dioxuslabs/dioxus.git" } [[bin]] path = "src/main.rs" diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..15935e2da --- /dev/null +++ b/build.rs @@ -0,0 +1,50 @@ +//! Construct version in the `commit-hash date channel` format + +use std::{env, path::PathBuf, process::Command}; + +fn main() { + set_rerun(); + set_commit_info(); + if option_env!("CFG_RELEASE").is_none() { + println!("cargo:rustc-env=POKE_RA_DEVS=1"); + } +} + +fn set_rerun() { + println!("cargo:rerun-if-env-changed=CFG_RELEASE"); + + let mut manifest_dir = PathBuf::from( + env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."), + ); + + while manifest_dir.parent().is_some() { + let head_ref = manifest_dir.join(".git/HEAD"); + if head_ref.exists() { + println!("cargo:rerun-if-changed={}", head_ref.display()); + return; + } + + manifest_dir.pop(); + } + + println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); +} + +fn set_commit_info() { + let output = match Command::new("git") + .arg("log") + .arg("-1") + .arg("--date=short") + .arg("--format=%H %h %cd") + .output() + { + Ok(output) if output.status.success() => output, + _ => return, + }; + let stdout = String::from_utf8(output.stdout).unwrap(); + let mut parts = stdout.split_whitespace(); + let mut next = || parts.next().unwrap(); + println!("cargo:rustc-env=RA_COMMIT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_DATE={}", next()) +} diff --git a/extension/dist/.gitignore b/extension/dist/.gitignore new file mode 100644 index 000000000..1287e9bd7 --- /dev/null +++ b/extension/dist/.gitignore @@ -0,0 +1,2 @@ +** +!.gitignore diff --git a/extension/package-lock.json b/extension/package-lock.json index 5de12fb6d..c671ca72c 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,92 +1,82 @@ { - "name": "dioxusstudio", + "name": "dioxus", "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "dioxusstudio", + "name": "dioxus", "version": "0.0.1", "license": "MIT", + "dependencies": { + "vsce": "^2.9.2" + }, "devDependencies": { - "@types/node": "^12.12.0", - "@types/vscode": "^1.32.0", - "@typescript-eslint/eslint-plugin": "^4.16.0", - "@typescript-eslint/parser": "^4.16.0", - "eslint": "^7.21.0", - "typescript": "^4.3.5" + "@types/node": "^18.0.2", + "@types/vscode": "^1.68.1", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "cross-env": "^7.0.3", + "esbuild": "^0.14.27", + "eslint": "^8.19.0", + "eslint-config-prettier": "^8.5.0", + "ovsx": "^0.5.1", + "prettier": "^2.6.2", + "tslib": "^2.3.0", + "typescript": "^4.7.4", + "vsce": "^2.7.0" }, "engines": { - "vscode": "^1.32.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "vscode": "^1.68.1" } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.4", + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { @@ -94,21 +84,21 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { @@ -116,48 +106,49 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/node": { - "version": "12.12.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.35.tgz", - "integrity": "sha512-ASYsaKecA7TUsDrqIGPNk3JeEox0z/0XR/WsJJ8BIX/9+SkMSImQXKWfU/yBrSyc7ZSE/NPqLu36Nur0miCFfQ==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.2.tgz", + "integrity": "sha512-b947SdS4GH+g2W33wf5FzUu1KLj5FcSIiNWbU1ZyMvt/X7w48ZsVcsQoirIgE/Oq03WT5Qbn/dkY0hePi4ZXcQ==", "dev": true }, "node_modules/@types/vscode": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.33.0.tgz", - "integrity": "sha512-JSmGiValbrcG5g20jjCfKakLiuWyrcjVezj+SEAEZ4klXQktE5EtowuGlkLVqbkiBK4iY5wy/4yW8OjecuHnjQ==", + "version": "1.68.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.1.tgz", + "integrity": "sha512-fXlaq13NT5yHh6yZ3c+UxXloTSk34mIvsNFYyQCeO5Po2BLFAwz7EZT4kQ43B64/aPcnAenyWy3QasrTofBOnQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz", - "integrity": "sha512-SK777klBdlkUZpZLC1mPvyOWk9yAFCWmug13eAjVQ4/Q1LATE/NbcQL1xDHkptQkZOLnPmLUA1Y54m8dqYwnoQ==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz", + "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.16.1", - "@typescript-eslint/scope-manager": "4.16.1", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/type-utils": "5.30.5", + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -165,50 +156,26 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz", - "integrity": "sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.16.1", - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/typescript-estree": "4.16.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.16.1.tgz", - "integrity": "sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz", + "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.16.1", - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/typescript-estree": "4.16.1", - "debug": "^4.1.1" + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -217,29 +184,55 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz", - "integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz", + "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/visitor-keys": "4.16.1" + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz", + "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz", - "integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz", + "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -247,21 +240,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz", - "integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz", + "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/visitor-keys": "4.16.1", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -273,36 +266,51 @@ } } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz", - "integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==", + "node_modules/@typescript-eslint/utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz", + "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.16.1", - "eslint-visitor-keys": "^2.0.0" + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz", + "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.5", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -312,9 +320,9 @@ } }, "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -336,44 +344,35 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -384,19 +383,57 @@ "node": ">=8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/azure-devops-node-api": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz", + "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" } }, "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, "node_modules/brace-expansion": { @@ -421,6 +458,52 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -431,9 +514,9 @@ } }, "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -446,22 +529,57 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">= 6" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, - "node_modules/chalk/node_modules/color-convert": { + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -473,54 +591,45 @@ "node": ">=7.0.0" } }, - "node_modules/chalk/node_modules/color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -535,22 +644,90 @@ "node": ">= 8" } }, - "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" } }, "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -575,74 +752,488 @@ "node": ">=6.0.0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "dependencies": { - "ansi-colors": "^4.1.1" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=8.6" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", - "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", - "minimatch": "^3.0.4", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -650,47 +1241,25 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", @@ -703,94 +1272,76 @@ "node": ">=8.0.0" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=6" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "engines": { "node": ">=10" } }, - "node_modules/eslint/node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "dependencies": { + "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint/node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/esquery": { @@ -806,26 +1357,35 @@ } }, "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" } }, "node_modules/esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" }, "engines": { "node": ">=4.0" } }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -844,6 +1404,15 @@ "node": ">=0.10.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -851,20 +1420,31 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/fast-json-stable-stringify": { @@ -876,18 +1456,27 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -926,33 +1515,85 @@ } }, "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -964,24 +1605,24 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", "dev": true, "dependencies": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" @@ -991,16 +1632,16 @@ } }, "node_modules/globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -1010,28 +1651,94 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, "engines": { - "node": ">= 4" + "node": ">= 0.4.0" } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" @@ -1056,7 +1763,7 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" @@ -1065,7 +1772,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -1078,28 +1785,37 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -1120,23 +1836,16 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -1151,9 +1860,29 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1167,10 +1896,19 @@ "node": ">= 0.8.0" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "node_modules/lru-cache": { @@ -1185,6 +1923,37 @@ "node": ">=10" } }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1195,22 +1964,46 @@ } }, "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -1219,22 +2012,85 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-abi": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz", + "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -1257,6 +2113,26 @@ "node": ">= 0.8.0" } }, + "node_modules/ovsx": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz", + "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==", + "dev": true, + "dependencies": { + "commander": "^6.1.0", + "follow-redirects": "^1.14.6", + "is-ci": "^2.0.0", + "leven": "^3.1.0", + "tmp": "^0.2.1", + "vsce": "^2.6.3" + }, + "bin": { + "ovsx": "lib/ovsx" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1269,10 +2145,53 @@ "node": ">=6" } }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dev": true, + "dependencies": { + "entities": "^4.3.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -1296,10 +2215,16 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -1308,6 +2233,32 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1317,13 +2268,29 @@ "node": ">= 0.8.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, "engines": { - "node": ">=0.4.0" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/punycode": { @@ -1335,10 +2302,25 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", - "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -1355,10 +2337,60 @@ } ] }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { "node": ">=8" @@ -1367,15 +2399,6 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1433,10 +2456,36 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1469,6 +2518,65 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1478,83 +2586,22 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "safe-buffer": "~5.2.0" } }, "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -1573,60 +2620,63 @@ } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "dependencies": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, - "node_modules/table/node_modules/ajv": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", - "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1640,15 +2690,15 @@ } }, "node_modules/tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "node_modules/tsutils": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", - "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "dependencies": { "tslib": "^1.8.1" @@ -1660,6 +2710,33 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1673,18 +2750,32 @@ } }, "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", + "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "dev": true, + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" } }, "node_modules/typescript": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", - "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1694,6 +2785,18 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", + "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", + "dev": true + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1703,12 +2806,138 @@ "punycode": "^2.1.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vsce": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz", + "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/vsce/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/vsce/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/vsce/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/vsce/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1736,218 +2965,241 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } } }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, "@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, - "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.4", + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/node": { - "version": "12.12.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.35.tgz", - "integrity": "sha512-ASYsaKecA7TUsDrqIGPNk3JeEox0z/0XR/WsJJ8BIX/9+SkMSImQXKWfU/yBrSyc7ZSE/NPqLu36Nur0miCFfQ==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.2.tgz", + "integrity": "sha512-b947SdS4GH+g2W33wf5FzUu1KLj5FcSIiNWbU1ZyMvt/X7w48ZsVcsQoirIgE/Oq03WT5Qbn/dkY0hePi4ZXcQ==", "dev": true }, "@types/vscode": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.33.0.tgz", - "integrity": "sha512-JSmGiValbrcG5g20jjCfKakLiuWyrcjVezj+SEAEZ4klXQktE5EtowuGlkLVqbkiBK4iY5wy/4yW8OjecuHnjQ==", + "version": "1.68.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.1.tgz", + "integrity": "sha512-fXlaq13NT5yHh6yZ3c+UxXloTSk34mIvsNFYyQCeO5Po2BLFAwz7EZT4kQ43B64/aPcnAenyWy3QasrTofBOnQ==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz", - "integrity": "sha512-SK777klBdlkUZpZLC1mPvyOWk9yAFCWmug13eAjVQ4/Q1LATE/NbcQL1xDHkptQkZOLnPmLUA1Y54m8dqYwnoQ==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz", + "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.16.1", - "@typescript-eslint/scope-manager": "4.16.1", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/type-utils": "5.30.5", + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz", - "integrity": "sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.16.1", - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/typescript-estree": "4.16.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.16.1.tgz", - "integrity": "sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz", + "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.16.1", - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/typescript-estree": "4.16.1", - "debug": "^4.1.1" + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz", - "integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz", + "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/visitor-keys": "4.16.1" + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz", + "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz", - "integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz", + "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz", - "integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz", + "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.16.1", - "@typescript-eslint/visitor-keys": "4.16.1", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz", + "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz", - "integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==", + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz", + "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.16.1", - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - } + "@typescript-eslint/types": "5.30.5", + "eslint-visitor-keys": "^3.3.0" } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "requires": {} }, @@ -1963,35 +3215,26 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-union": { "version": "2.1.0", @@ -1999,16 +3242,43 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true + "azure-devops-node-api": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz", + "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==", + "dev": true, + "requires": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } }, "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, "brace-expansion": { @@ -2030,6 +3300,32 @@ "fill-range": "^7.0.1" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2037,77 +3333,92 @@ "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "dev": true, "requires": { - "color-name": "1.1.3" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2119,19 +3430,59 @@ "which": "^2.0.1" } }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, "requires": { - "ms": "^2.1.1" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" } }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", "dev": true }, "dir-glob": { @@ -2152,174 +3503,344 @@ "esutils": "^2.0.2" } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "requires": { - "ansi-colors": "^4.1.1" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" } }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "dev": true + }, + "esbuild": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", + "dev": true, + "optional": true + }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", - "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", - "minimatch": "^3.0.4", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true } } }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "requires": {} + }, "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -2330,20 +3851,28 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "estraverse": { @@ -2358,6 +3887,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2365,17 +3900,27 @@ "dev": true }, "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "fast-json-stable-stringify": { @@ -2387,18 +3932,27 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2428,87 +3982,156 @@ } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" } }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "import-fresh": { @@ -2524,13 +4147,13 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -2543,22 +4166,31 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -2573,23 +4205,16 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "json-schema-traverse": { @@ -2601,7 +4226,23 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "requires": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, "levn": { @@ -2614,10 +4255,19 @@ "type-check": "~0.4.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lru-cache": { @@ -2629,6 +4279,33 @@ "yallist": "^4.0.0" } }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2636,40 +4313,106 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-abi": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz", + "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -2689,6 +4432,20 @@ "word-wrap": "^1.2.3" } }, + "ovsx": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz", + "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==", + "dev": true, + "requires": { + "commander": "^6.1.0", + "follow-redirects": "^1.14.6", + "is-ci": "^2.0.0", + "leven": "^3.1.0", + "tmp": "^0.2.1", + "vsce": "^2.6.3" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2698,10 +4455,46 @@ "callsites": "^3.0.0" } }, + "parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "requires": { + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dev": true, + "requires": { + "entities": "^4.3.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { @@ -2716,46 +4509,125 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "queue-microtask": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", - "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "resolve-from": { @@ -2788,10 +4660,22 @@ "queue-microtask": "^1.2.2" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2812,73 +4696,56 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "safe-buffer": "~5.2.0" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { @@ -2888,52 +4755,54 @@ "dev": true }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, - "table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "requires": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ajv": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", - "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2944,18 +4813,41 @@ } }, "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "tsutils": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", - "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" } }, "type-check": { @@ -2968,15 +4860,38 @@ } }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typed-rest-client": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", + "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "dev": true, + "requires": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "typescript": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", - "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", + "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", "dev": true }, "uri-js": { @@ -2988,12 +4903,116 @@ "punycode": "^2.1.0" } }, - "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vsce": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz", + "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3012,7 +5031,23 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, "yallist": { @@ -3020,6 +5055,25 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } } } } diff --git a/extension/package.json b/extension/package.json index f884637c8..3e4ca4b83 100644 --- a/extension/package.json +++ b/extension/package.json @@ -12,10 +12,10 @@ "url": "https://github.com/DioxusLabs/cli" }, "engines": { - "vscode": "^1.32.0" + "vscode": "^1.68.1" }, "categories": [ - "Other" + "Programming Languages" ], "activationEvents": [ "onCommand:extension.htmlToDioxusRsx", @@ -23,7 +23,7 @@ "onCommand:extension.formatRsx", "onCommand:extension.formatRsxDocument" ], - "main": "./out/extension", + "main": "./out/main", "contributes": { "commands": [ { @@ -45,18 +45,32 @@ ] }, "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./", - "lint": "eslint . --ext .ts,.tsx", - "watch": "tsc -watch -p ./", - "package": "vsce package" + "vscode:prepublish": "npm run build-base -- --minify", + "package": "vsce package -o rust-analyzer.vsix", + "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16", + "build": "npm run build-base -- --sourcemap", + "watch": "npm run build-base -- --sourcemap --watch", + "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests", + "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", + "pretest": "tsc && npm run build", + "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js" }, "devDependencies": { - "@types/node": "^12.12.0", - "@types/vscode": "^1.32.0", - "@typescript-eslint/eslint-plugin": "^4.16.0", - "@typescript-eslint/parser": "^4.16.0", - "eslint": "^7.21.0", - "typescript": "^4.3.5" + "@types/node": "^18.0.2", + "@types/vscode": "^1.68.1", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "cross-env": "^7.0.3", + "esbuild": "^0.14.27", + "eslint": "^8.19.0", + "typescript": "^4.7.4", + "eslint-config-prettier": "^8.5.0", + "ovsx": "^0.5.1", + "prettier": "^2.6.2", + "tslib": "^2.3.0", + "vsce": "^2.7.0" + }, + "dependencies": { + "vsce": "^2.9.2" } } diff --git a/extension/server/.gitignore b/extension/server/.gitignore new file mode 100644 index 000000000..f42761bea --- /dev/null +++ b/extension/server/.gitignore @@ -0,0 +1,3 @@ +** +!Readme.md +!.gitignore diff --git a/extension/src/extension.ts b/extension/src/extension.ts deleted file mode 100644 index 44d5b8f16..000000000 --- a/extension/src/extension.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as vscode from 'vscode'; -import { spawn } from "child_process"; - -export function activate(context: vscode.ExtensionContext) { - - - function translate(component: boolean) { - const editor = vscode.window.activeTextEditor;// Get the active text editor - if (!editor) return; - - const html = editor.document.getText(editor.selection); - if (html.length == 0) { - vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!"); - return; - } - - let params = ["translate"]; - if (component) params.push("--component"); - params.push("--raw"); - params.push(html); - - const child_proc = spawn("dioxus", params); - - let result = ''; - child_proc.stdout?.on('data', data => result += data); - - child_proc.on('close', () => { - if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); - }); - - child_proc.on('error', (err) => { - vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); - }); - } - - function autoformat_selection() { - const editor = vscode.window.activeTextEditor;// Get the active text editor - if (!editor) return; - - const unformatted = editor.document.getText(editor.selection); - if (unformatted.length == 0) { - vscode.window.showWarningMessage("Please select rsx invoking this command!"); - return; - } - - let args = ["fmt", "--raw", unformatted.toString()]; - const child_proc = spawn("dioxus", args); - let result = ''; - - child_proc.stdout?.on('data', data => result += data); - - child_proc.on('close', () => { - if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); - }); - - child_proc.on('error', (err) => { - vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); - }); - } - - - function autoformat_document(document: vscode.TextDocument) { - // check the settings to make sure format on save is configured - // const formatOnSave: string | undefined = vscode.workspace.getConfiguration('rust').get('formatOnSave'); - - if (document.languageId === "rust" && document.uri.scheme === "file") { - const active_editor = vscode.window.activeTextEditor;// Get the active text editor - - if (active_editor?.document.fileName === document.fileName) { - const text = document.getText(); - - console.error(text); - - const child_proc = spawn("dioxus", ["fmt", "-f", text]); - - let result = ''; - - child_proc.stdout?.on('data', data => result += data); - - type RsxEdit = { - formatted: string, - start: number, - end: number - } - - child_proc.on('close', () => { - - if (result.length > 0) { - let decoded: RsxEdit[] = JSON.parse(result); - - console.log("Decoded edits: ", decoded); - - // Get the active text editor - const cur_editor = vscode.window.activeTextEditor; - - - // even if we build an empty edit stream, it tries to save the editor - // this makes sure the editor is actually saved - if (decoded.length > 0 && cur_editor == active_editor) { - active_editor.edit(editBuilder => { - - for (let edit of decoded) { - console.log("Handling Edit: ", edit); - - let start = document.positionAt(edit.start - 1); - let end = document.positionAt(edit.end + 1); - const range = new vscode.Range(start, end); - - editBuilder.replace(range, `{ ${edit.formatted} }`); - // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { - // }); - // editor.edit(editBuilder => editBuilder.replace(range, `{ ${edit.formatted} }`)).then((could_be_applied) => { - // console.log("Edit applied: ", could_be_applied); - // }); - } - }) - } - } - }); - - child_proc.on('error', (err) => { - vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); - }); - } - } - } - - context.subscriptions.push( - vscode.commands.registerCommand('extension.htmlToDioxusRsx', () => translate(false)), - vscode.commands.registerCommand('extension.htmlToDioxusComponent', () => translate(true)), - vscode.commands.registerCommand('extension.formatRsx', () => autoformat_selection()), - vscode.commands.registerCommand('extension.formatRsxDocument', () => { - const editor = vscode.window.activeTextEditor;// Get the active text editor - if (!editor) return; - autoformat_document(editor.document); - }), - vscode.workspace.onDidSaveTextDocument(autoformat_document) - ); -} diff --git a/extension/src/main.ts b/extension/src/main.ts new file mode 100644 index 000000000..156d45565 --- /dev/null +++ b/extension/src/main.ts @@ -0,0 +1,184 @@ +import * as vscode from 'vscode'; +import { spawn } from "child_process"; + +let serverPath: string = "dioxus"; + +export async function activate(context: vscode.ExtensionContext) { + let somePath = await bootstrap(context); + + if (somePath == undefined) { + await vscode.window.showErrorMessage('Could not find bundled Dioxus-CLI. Please install it manually.'); + return; + } else { + serverPath = somePath; + } + + context.subscriptions.push( + vscode.commands.registerTextEditorCommand('editor.action.clipboardPasteAction', onPasteHandler), + vscode.commands.registerCommand('extension.htmlToDioxusRsx', translateBlock), + vscode.commands.registerCommand('extension.htmlToDioxusComponent', translateComponent), + vscode.commands.registerCommand('extension.formatRsx', fmtSelection), + vscode.commands.registerCommand('extension.formatRsxDocument', formatRsxDocument), + vscode.workspace.onWillSaveTextDocument(fmtDocument) + ); +} + + +function translateComponent() { + translate(true) +} + +function translateBlock() { + translate(false) +} + +function translate(component: boolean) { + const editor = vscode.window.activeTextEditor; + + if (!editor) return; + + const html = editor.document.getText(editor.selection); + if (html.length == 0) { + vscode.window.showWarningMessage("Please select HTML fragment before invoking this command!"); + return; + } + + let params = ["translate"]; + if (component) params.push("--component"); + params.push("--raw", html); + + const child_proc = spawn(serverPath, params); + + let result = ''; + child_proc.stdout?.on('data', data => result += data); + + child_proc.on('close', () => { + if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); +} + +function onPasteHandler() { + // check settings to see if we should convert HTML to Rsx + if (vscode.workspace.getConfiguration('dioxus').get('convertOnPaste')) { + convertHtmlToRsxOnPaste(); + } +} + +function convertHtmlToRsxOnPaste() { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + + // get the cursor location + const cursor = editor.selection.active; + + // try to parse the HTML at the cursor location + const html = editor.document.getText(new vscode.Range(cursor, cursor)); +} + +function formatRsxDocument() { + const editor = vscode.window.activeTextEditor; + if (editor) { + fmtDocument(); + } +} + +function fmtSelection() { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + + const unformatted = editor.document.getText(editor.selection); + + if (unformatted.length == 0) { + vscode.window.showWarningMessage("Please select rsx invoking this command!"); + return; + } + + const child_proc = spawn(serverPath, ["fmt", "--raw", unformatted.toString()]); + let result = ''; + + child_proc.stdout?.on('data', data => result += data); + + child_proc.on('close', () => { + if (result.length > 0) editor.edit(editBuilder => editBuilder.replace(editor.selection, result)); + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); +} + +function fmtDocument() { + const editor = vscode.window.activeTextEditor; + const document = editor?.document; + if (!document) return; + + // check the settings to make sure format on save is configured + if (document.languageId === "rust" && document.uri.scheme === "file") { + const active_editor = vscode.window.activeTextEditor; + + if (active_editor?.document.fileName === document.fileName) { + const text = document.getText(); + const child_proc = spawn("dioxus", ["fmt", "-f", text]); + + let result = ''; + child_proc.stdout?.on('data', data => result += data); + + type RsxEdit = { + formatted: string, + start: number, + end: number + } + + child_proc.on('close', () => { + if (result.length > 0) { + let decoded: RsxEdit[] = JSON.parse(result); + + if (decoded.length > 0) { + active_editor.edit(editBuilder => { + decoded.map((edit) => { + editBuilder.replace(new vscode.Range( + document.positionAt(edit.start), + document.positionAt(edit.end) + ), edit.formatted); + }); + }, { + undoStopAfter: false, + undoStopBefore: false + }) + } + } + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); + } + } +} + + +// I'm using the approach defined in rust-analyzer here +// +// We ship the server as part of the extension, but we need to handle external paths and such +// +// https://github.com/rust-lang/rust-analyzer/blob/fee5555cfabed4b8abbd40983fc4442df4007e49/editors/code/src/main.ts#L270 +async function bootstrap(context: vscode.ExtensionContext): Promise { + + const ext = process.platform === "win32" ? ".exe" : ""; + const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `dioxus${ext}`); + const bundledExists = await vscode.workspace.fs.stat(bundled).then( + () => true, + () => false + ); + + // if bunddled doesn't exist, try using a locally-installed version + if (!bundledExists) { + return "dioxus"; + } + + return bundled.fsPath; +} diff --git a/src/cli/autoformat/mod.rs b/src/cli/autoformat/mod.rs index 3008411db..5c1532d58 100644 --- a/src/cli/autoformat/mod.rs +++ b/src/cli/autoformat/mod.rs @@ -15,7 +15,7 @@ pub struct Autoformat { impl Autoformat { pub fn autoformat(self) -> Result<()> { if let Some(raw) = self.raw { - if let Some(inner) = dioxus_autofmt::fmt_block(&raw) { + if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0) { println!("{}", inner); } else { // exit process with error @@ -25,7 +25,7 @@ impl Autoformat { } if let Some(file) = self.file { - let edits = dioxus_autofmt::get_format_blocks(&file); + let edits = dioxus_autofmt::fmt_file(&file); let as_json = serde_json::to_string(&edits).unwrap(); println!("{}", as_json); } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 92e05eaa9..efd72b3cd 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -7,6 +7,7 @@ pub mod create; pub mod serve; pub mod tool; pub mod translate; +pub mod version; use crate::{ cfg::{ConfigOptsBuild, ConfigOptsServe}, @@ -59,6 +60,10 @@ pub enum Commands { /// Clean output artifacts. Clean(clean::Clean), + /// Print the version of this extension + #[clap(name = "version")] + Version(version::Version), + /// Format some rsx #[clap(name = "fmt")] Autoformat(autoformat::Autoformat), diff --git a/src/cli/version.rs b/src/cli/version.rs new file mode 100644 index 000000000..3c77ba419 --- /dev/null +++ b/src/cli/version.rs @@ -0,0 +1,76 @@ +use super::*; + +/// Build the Rust WASM app and all of its assets. +#[derive(Clone, Debug, Parser)] +#[clap(name = "version")] +pub struct Version {} + +impl Version { + pub fn version(self) -> VersionInfo { + version() + } +} + +use std::fmt; + +/// Information about the git repository where rust-analyzer was built from. +pub struct CommitInfo { + pub short_commit_hash: &'static str, + pub commit_hash: &'static str, + pub commit_date: &'static str, +} + +/// Cargo's version. +pub struct VersionInfo { + /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc. + pub version: &'static str, + + /// The release channel we were built for (stable/beta/nightly/dev). + /// + /// `None` if not built via rustbuild. + pub release_channel: Option<&'static str>, + + /// Information about the Git repository we may have been built from. + /// + /// `None` if not built from a git repo. + pub commit_info: Option, +} + +impl fmt::Display for VersionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.version)?; + + if let Some(ci) = &self.commit_info { + write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; + }; + Ok(()) + } +} + +/// Returns information about cargo's version. +pub const fn version() -> VersionInfo { + let version = match option_env!("CFG_RELEASE") { + Some(x) => x, + None => "0.0.0", + }; + + let release_channel = option_env!("CFG_RELEASE_CHANNEL"); + let commit_info = match ( + option_env!("RA_COMMIT_SHORT_HASH"), + option_env!("RA_COMMIT_HASH"), + option_env!("RA_COMMIT_DATE"), + ) { + (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => Some(CommitInfo { + short_commit_hash, + commit_hash, + commit_date, + }), + _ => None, + }; + + VersionInfo { + version, + release_channel, + commit_info, + } +} diff --git a/src/main.rs b/src/main.rs index 72558741e..f72cb7666 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,11 @@ async fn main() -> Result<()> { log::error!("format error: {}", e); } } + + Commands::Version(opt) => { + let version = opt.version(); + println!("{}", version); + } } Ok(()) From 719e48c0a5f36cad505d2b0b6dd4a2bc9b212a6e Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:16:16 +0800 Subject: [PATCH 156/895] feat: beautify console --- Cargo.toml | 3 ++- src/cli/mod.rs | 6 +----- src/lib.rs | 4 +++- src/server/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42de2ba4c..fa14b36b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dioxus-cli" -version = "0.1.4" +version = "0.1.5" authors = ["Jonathan Kelley"] edition = "2021" description = "CLI tool for developing, testing, and publishing Dioxus apps" @@ -14,6 +14,7 @@ license = "MIT/Apache-2.0" clap = { version = "3.0.14", features = ["derive"] } thiserror = "1.0.30" wasm-bindgen-cli-support = "0.2.79" +colored = "2.0.0" # features log = "0.4.14" diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d639d28a7..b456d4705 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -27,7 +27,7 @@ use std::{ /// Build, bundle, & ship your Dioxus app. #[derive(Parser)] -#[clap(name = "dioxus")] +#[clap(name = "dioxus", version)] pub struct Cli { #[clap(subcommand)] pub action: Commands, @@ -35,10 +35,6 @@ pub struct Cli { /// Enable verbose logging. #[clap(short)] pub v: bool, - // // note: dioxus is still roughly compatible with trunk - // /// Path to the Trunk config file [default: Trunk.toml] - // #[clap(long, parse(from_os_str), env = "TRUNK_CONFIG")] - // pub config: Option, } #[derive(Parser)] diff --git a/src/lib.rs b/src/lib.rs index 6d009c18c..9956989b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +pub const DIOXUS_CLI_VERSION: &'static str = "0.1.5"; + pub mod builder; pub mod server; pub mod tools; @@ -19,4 +21,4 @@ pub use error::*; pub mod logging; pub use logging::*; -pub mod hot_reload; +pub mod hot_reload; \ No newline at end of file diff --git a/src/server/mod.rs b/src/server/mod.rs index 446d9d75c..886088fd9 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,11 +6,12 @@ use axum::{ routing::{get, get_service}, Router, }; +use colored::Colorize; use dioxus::rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; use syn::spanned::Spanned; -use std::{path::PathBuf, sync::Arc}; +use std::{path::PathBuf, process::Command, sync::Arc}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; @@ -180,7 +181,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0:8080 - log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); + print_console_info(port, &config); let file_service_config = config.clone(); let file_service = ServiceBuilder::new() @@ -290,7 +291,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0 - log::info!("📡 Dev-Server is started at: http://127.0.0.1:{}/", port); + print_console_info(port, &config); let file_service_config = config.clone(); let file_service = ServiceBuilder::new() @@ -348,6 +349,44 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { Ok(()) } +fn print_console_info(port: u16, config: &CrateConfig) { + print!( + "{}", + String::from_utf8_lossy( + &Command::new(if cfg!(target_os = "windows") { + "cls" + } else { + "clear" + }) + .output() + .unwrap() + .stdout + ) + ); + + let mut profile = if config.release { "Release" } else { "Debug" }.to_string(); + if config.custom_profile.is_some() { + profile = config.custom_profile.as_ref().unwrap().to_string(); + } + let hot_reload = if config.hot_reload { "RSX" } else { "Normal" }; + let workspace = config.workspace_dir.to_str().unwrap().to_string(); + + println!( + "{} @ v{}\n", + "Dioxus".bold().green(), + crate::DIOXUS_CLI_VERSION + ); + println!( + "\t> Local: {}", + format!("https://localhost:{}/", port).blue() + ); + println!("\t> Profile: {}", profile.green()); + println!("\t> Hot Reload: {}", hot_reload.green()); + println!("\t> Workspace: {}", workspace.yellow()); + + println!("\n{}", "Server startup completed.".bold()); +} + async fn ws_handler( ws: WebSocketUpgrade, _: Option>, From b2c5141fa6f62b4eaf3e4918dc5b6e29c2209785 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:36:14 +0800 Subject: [PATCH 157/895] feat: commit code --- src/server/mod.rs | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 886088fd9..b1e527b86 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -369,22 +369,54 @@ fn print_console_info(port: u16, config: &CrateConfig) { profile = config.custom_profile.as_ref().unwrap().to_string(); } let hot_reload = if config.hot_reload { "RSX" } else { "Normal" }; - let workspace = config.workspace_dir.to_str().unwrap().to_string(); + let tools_str = format!( + "{:?}", + config + .dioxus_config + .application + .tools + .clone() + .unwrap_or_default() + .iter() + .map(|d| d.0.clone()) + .collect::>() + ); + let crate_root = crate::cargo::crate_root().unwrap(); + let custom_html_file = if crate_root.join("index.html").is_file() { + "Custom [index.html]" + } else { + "Default" + }; + let url_rewrite = if config + .dioxus_config + .web + .watcher + .index_on_404 + .unwrap_or(false) + { + "True" + } else { + "False" + }; println!( "{} @ v{}\n", "Dioxus".bold().green(), - crate::DIOXUS_CLI_VERSION + crate::DIOXUS_CLI_VERSION, ); println!( - "\t> Local: {}", + "\t> Local : {}", format!("https://localhost:{}/", port).blue() ); - println!("\t> Profile: {}", profile.green()); - println!("\t> Hot Reload: {}", hot_reload.green()); - println!("\t> Workspace: {}", workspace.yellow()); + println!("\t> NetWork : {}", "use --host to expose".white().dimmed()); + println!(""); + println!("\t> Profile : {}", profile.green()); + println!("\t> Hot Reload : {}", hot_reload.cyan()); + println!("\t> Enabled Tools : {}", tools_str.yellow()); + println!("\t> Index Template : {}", custom_html_file.green()); + println!("\t> URL Rewrite : {}", url_rewrite.purple()); - println!("\n{}", "Server startup completed.".bold()); + println!("\n{}", "Server startup completed.\n".bold()); } async fn ws_handler( From 9e64b5dde88609d43ac14cccc571b39318356c05 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:46:46 +0800 Subject: [PATCH 158/895] feat: commit code --- src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index b1e527b86..87448cda9 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -416,7 +416,7 @@ fn print_console_info(port: u16, config: &CrateConfig) { println!("\t> Index Template : {}", custom_html_file.green()); println!("\t> URL Rewrite : {}", url_rewrite.purple()); - println!("\n{}", "Server startup completed.\n".bold()); + println!("\n{}\n", "Server startup completed.".green().bold()); } async fn ws_handler( From 8dbf571891bad849eb54c57bddd3849f1c02e8bf Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 18:11:25 +0800 Subject: [PATCH 159/895] feat: commit console print --- src/server/mod.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 87448cda9..93e81ea33 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -11,7 +11,7 @@ use dioxus::rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; use syn::spanned::Spanned; -use std::{path::PathBuf, process::Command, sync::Arc}; +use std::{path::PathBuf, process::Command, sync::Arc, net::UdpSocket}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; @@ -408,17 +408,41 @@ fn print_console_info(port: u16, config: &CrateConfig) { "\t> Local : {}", format!("https://localhost:{}/", port).blue() ); - println!("\t> NetWork : {}", "use --host to expose".white().dimmed()); + println!( + "\t> NetWork : {}", + format!( + "http://{}:{}/", + get_ip().unwrap_or(String::from("0.0.0.0")), + port + ).blue() + ); println!(""); println!("\t> Profile : {}", profile.green()); println!("\t> Hot Reload : {}", hot_reload.cyan()); println!("\t> Enabled Tools : {}", tools_str.yellow()); println!("\t> Index Template : {}", custom_html_file.green()); - println!("\t> URL Rewrite : {}", url_rewrite.purple()); + println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple()); println!("\n{}\n", "Server startup completed.".green().bold()); } +fn get_ip() -> Option { + let socket = match UdpSocket::bind("0.0.0.0:0") { + Ok(s) => s, + Err(_) => return None, + }; + + match socket.connect("8.8.8.8:80") { + Ok(()) => (), + Err(_) => return None, + }; + + match socket.local_addr() { + Ok(addr) => return Some(addr.ip().to_string()), + Err(_) => return None, + }; +} + async fn ws_handler( ws: WebSocketUpgrade, _: Option>, From 81b712ec0baab63186769cfa62b1962bfd90af24 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 21:08:46 +0800 Subject: [PATCH 160/895] feat: commit code --- src/server/mod.rs | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 93e81ea33..c5b438768 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -11,7 +11,7 @@ use dioxus::rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; use syn::spanned::Spanned; -use std::{path::PathBuf, process::Command, sync::Arc, net::UdpSocket}; +use std::{net::UdpSocket, path::PathBuf, process::Command, sync::Arc}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; @@ -270,12 +270,17 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); - let mut watcher = RecommendedWatcher::new(move |_: notify::Result| { - // log::info!("🚧 reload required"); - if chrono::Local::now().timestamp() > last_update_time { - match build_manager.build() { - Ok(_) => last_update_time = chrono::Local::now().timestamp(), - Err(e) => log::error!("{}", e), + let mut watcher = RecommendedWatcher::new(move |info: notify::Result| { + if info.is_ok() { + let info = info.unwrap(); + if chrono::Local::now().timestamp() > last_update_time { + match build_manager.build() { + Ok(_) => { + last_update_time = chrono::Local::now().timestamp(); + print_rebuild_info(info.paths); + } + Err(e) => log::error!("{}", e), + } } } }) @@ -414,7 +419,8 @@ fn print_console_info(port: u16, config: &CrateConfig) { "http://{}:{}/", get_ip().unwrap_or(String::from("0.0.0.0")), port - ).blue() + ) + .blue() ); println!(""); println!("\t> Profile : {}", profile.green()); @@ -426,6 +432,28 @@ fn print_console_info(port: u16, config: &CrateConfig) { println!("\n{}\n", "Server startup completed.".green().bold()); } +fn print_rebuild_info(paths: Vec) { + print!( + "{}", + String::from_utf8_lossy( + &Command::new(if cfg!(target_os = "windows") { + "cls" + } else { + "clear" + }) + .output() + .unwrap() + .stdout + ) + ); + + for path in paths { + let path = path.strip_prefix(crate::crate_root().unwrap()).unwrap().to_path_buf(); + log::info!("Updated {}", format!("{}", path.to_str().unwrap()).green()); + } + log::info!("Project rebuild done.") +} + fn get_ip() -> Option { let socket = match UdpSocket::bind("0.0.0.0:0") { Ok(s) => s, From 61c06ea5987ada72528d7625380c69a0cea5c5d2 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 21:23:35 +0800 Subject: [PATCH 161/895] feat: commit console log --- src/builder.rs | 6 +++++- src/cli/build/mod.rs | 2 +- src/cli/serve/mod.rs | 2 +- src/server/hot_reload.rs | 2 +- src/server/mod.rs | 36 ++++++++++++++++++------------------ 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 02add84ad..f69ce3637 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -13,7 +13,7 @@ use std::{ }; use wasm_bindgen_cli_support::Bindgen; -pub fn build(config: &CrateConfig) -> Result<()> { +pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) // [2] Generate the appropriate build folders // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm @@ -52,6 +52,10 @@ pub fn build(config: &CrateConfig) -> Result<()> { cmd.arg("--verbose"); } + if quiet { + cmd.arg("--quiet"); + } + if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); cmd.arg("--profile"); diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs index 661f17a5a..f857bfc13 100644 --- a/src/cli/build/mod.rs +++ b/src/cli/build/mod.rs @@ -34,7 +34,7 @@ impl Build { match platform.as_str() { "web" => { - crate::builder::build(&crate_config)?; + crate::builder::build(&crate_config, false)?; } "desktop" => { crate::builder::build_desktop(&crate_config, false)?; diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 5528ebade..62843d653 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -40,7 +40,7 @@ impl Serve { match platform.as_str() { "web" => { - crate::builder::build(&crate_config)?; + crate::builder::build(&crate_config, false)?; } "desktop" => { crate::builder::build_desktop(&crate_config, true)?; diff --git a/src/server/hot_reload.rs b/src/server/hot_reload.rs index 0338dacc5..3b7812834 100644 --- a/src/server/hot_reload.rs +++ b/src/server/hot_reload.rs @@ -154,7 +154,7 @@ pub async fn hot_reload_handler( log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file_path, parse_error.location.line, parse_error.location.column, parse_error.message); }, Error::RecompileRequiredError(_) => { - if let Err(err) = state.build_manager.build(){ + if let Err(err) = state.build_manager.rebuild(){ log::error!("{}", err); } } diff --git a/src/server/mod.rs b/src/server/mod.rs index c5b438768..6b0b90a68 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -27,9 +27,9 @@ pub struct BuildManager { } impl BuildManager { - fn build(&self) -> Result<()> { - log::info!("🪁 Rebuild code"); - builder::build(&self.config)?; + fn rebuild(&self) -> Result<()> { + log::info!("🪁 Rebuild project"); + builder::build(&self.config, true)?; // change the websocket reload state to true; // the page will auto-reload. if self @@ -158,7 +158,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } if needs_rebuild { log::info!("reload required"); - if let Err(err) = build_manager.build() { + if let Err(err) = build_manager.rebuild() { log::error!("{}", err); } } @@ -274,7 +274,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { if info.is_ok() { let info = info.unwrap(); if chrono::Local::now().timestamp() > last_update_time { - match build_manager.build() { + match build_manager.rebuild() { Ok(_) => { last_update_time = chrono::Local::now().timestamp(); print_rebuild_info(info.paths); @@ -433,19 +433,19 @@ fn print_console_info(port: u16, config: &CrateConfig) { } fn print_rebuild_info(paths: Vec) { - print!( - "{}", - String::from_utf8_lossy( - &Command::new(if cfg!(target_os = "windows") { - "cls" - } else { - "clear" - }) - .output() - .unwrap() - .stdout - ) - ); + // print!( + // "{}", + // String::from_utf8_lossy( + // &Command::new(if cfg!(target_os = "windows") { + // "cls" + // } else { + // "clear" + // }) + // .output() + // .unwrap() + // .stdout + // ) + // ); for path in paths { let path = path.strip_prefix(crate::crate_root().unwrap()).unwrap().to_path_buf(); From 14a2ec306eb64e1ad8a5a293c0225dbfd1d29487 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:37:27 +0800 Subject: [PATCH 162/895] feat: commit code --- src/server/mod.rs | 62 +++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 6b0b90a68..ba9a853f6 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -181,7 +181,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0:8080 - print_console_info(port, &config); + print_console_info(port, &config, vec![]); let file_service_config = config.clone(); let file_service = ServiceBuilder::new() @@ -270,15 +270,14 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); + let watcher_config = config.clone(); let mut watcher = RecommendedWatcher::new(move |info: notify::Result| { + let config = watcher_config.clone(); if info.is_ok() { - let info = info.unwrap(); + print_console_info(port, &config, info.unwrap().paths); if chrono::Local::now().timestamp() > last_update_time { match build_manager.rebuild() { - Ok(_) => { - last_update_time = chrono::Local::now().timestamp(); - print_rebuild_info(info.paths); - } + Ok(_) => last_update_time = chrono::Local::now().timestamp(), Err(e) => log::error!("{}", e), } } @@ -296,7 +295,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0 - print_console_info(port, &config); + print_console_info(port, &config, vec![]); let file_service_config = config.clone(); let file_service = ServiceBuilder::new() @@ -354,7 +353,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { Ok(()) } -fn print_console_info(port: u16, config: &CrateConfig) { +fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { print!( "{}", String::from_utf8_lossy( @@ -369,6 +368,14 @@ fn print_console_info(port: u16, config: &CrateConfig) { ) ); + // for path in &changed { + // let path = path + // .strip_prefix(crate::crate_root().unwrap()) + // .unwrap() + // .to_path_buf(); + // log::info!("Updated {}", format!("{}", path.to_str().unwrap()).green()); + // } + let mut profile = if config.release { "Release" } else { "Debug" }.to_string(); if config.custom_profile.is_some() { profile = config.custom_profile.as_ref().unwrap().to_string(); @@ -404,11 +411,18 @@ fn print_console_info(port: u16, config: &CrateConfig) { "False" }; - println!( - "{} @ v{}\n", - "Dioxus".bold().green(), - crate::DIOXUS_CLI_VERSION, - ); + if changed.len() <= 0 { + println!( + "{} @ v{}\n", + "Dioxus".bold().green(), + crate::DIOXUS_CLI_VERSION, + ); + } else { + println!( + "Project Reloaded: {}\n", + format!("Changed {} files.", changed.len()).purple().bold() + ); + } println!( "\t> Local : {}", format!("https://localhost:{}/", port).blue() @@ -432,28 +446,6 @@ fn print_console_info(port: u16, config: &CrateConfig) { println!("\n{}\n", "Server startup completed.".green().bold()); } -fn print_rebuild_info(paths: Vec) { - // print!( - // "{}", - // String::from_utf8_lossy( - // &Command::new(if cfg!(target_os = "windows") { - // "cls" - // } else { - // "clear" - // }) - // .output() - // .unwrap() - // .stdout - // ) - // ); - - for path in paths { - let path = path.strip_prefix(crate::crate_root().unwrap()).unwrap().to_path_buf(); - log::info!("Updated {}", format!("{}", path.to_str().unwrap()).green()); - } - log::info!("Project rebuild done.") -} - fn get_ip() -> Option { let socket = match UdpSocket::bind("0.0.0.0:0") { Ok(s) => s, From 3551d1b6a0aeeebc3d52e5399f4f0e70703df325 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:44:50 +0800 Subject: [PATCH 163/895] feat: commit code --- src/server/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index ba9a853f6..d6efab958 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -94,14 +94,16 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { .clone() .unwrap_or_else(|| vec![PathBuf::from("src")]); + let watcher_config = config.clone(); let mut watcher = RecommendedWatcher::new(move |evt: notify::Result| { + let config = watcher_config.clone(); if chrono::Local::now().timestamp() > last_update_time { // Give time for the change to take effect before reading the file std::thread::sleep(std::time::Duration::from_millis(100)); if let Ok(evt) = evt { let mut messages = Vec::new(); let mut needs_rebuild = false; - for path in evt.paths { + for path in evt.paths.clone() { let mut file = File::open(path.clone()).unwrap(); if path.extension().map(|p| p.to_str()).flatten() != Some("rs") { continue; @@ -157,7 +159,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } } if needs_rebuild { - log::info!("reload required"); + print_console_info(port, &config, evt.paths); if let Err(err) = build_manager.rebuild() { log::error!("{}", err); } From b642dcd739a0403837ca43cd661d8d24ac22012d Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:45:08 +0800 Subject: [PATCH 164/895] fix: format code --- src/builder.rs | 4 +++- src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f69ce3637..4feb87839 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -433,7 +433,9 @@ fn build_assets(config: &CrateConfig) -> Result> { let temp = entry.path(); if temp.is_file() { let suffix = temp.extension(); - if suffix.is_none() { continue; } + if suffix.is_none() { + continue; + } let suffix = suffix.unwrap().to_str().unwrap(); if suffix == "scss" || suffix == "sass" { // if file suffix is `scss` / `sass` we need transform it. diff --git a/src/lib.rs b/src/lib.rs index 9956989b7..1b651acee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,4 +21,4 @@ pub use error::*; pub mod logging; pub use logging::*; -pub mod hot_reload; \ No newline at end of file +pub mod hot_reload; From f57dc5212b37bcc799feded01468c0251f60822a Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Wed, 6 Jul 2022 23:01:39 +0800 Subject: [PATCH 165/895] fix: change local `https` to `http` --- src/server/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index d6efab958..3ecce6c26 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -427,7 +427,7 @@ fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { } println!( "\t> Local : {}", - format!("https://localhost:{}/", port).blue() + format!("http://localhost:{}/", port).blue() ); println!( "\t> NetWork : {}", @@ -444,8 +444,14 @@ fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { println!("\t> Enabled Tools : {}", tools_str.yellow()); println!("\t> Index Template : {}", custom_html_file.green()); println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple()); + println!(""); - println!("\n{}\n", "Server startup completed.".green().bold()); + if changed.len() <= 0 { + log::info!("{}", "Server startup completed.".green().bold()); + } else { + log::info!("{}", "Project rebuild completed.".green().bold()); + } + } fn get_ip() -> Option { From 7860f8b931ecf7d5757433f53868561929d95e74 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Thu, 7 Jul 2022 23:03:30 +0800 Subject: [PATCH 166/895] feat: commit code --- Cargo.toml | 1 + src/builder.rs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa14b36b7..7e982bc78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ regex = "1.5.4" chrono = "0.4.19" anyhow = "1.0.53" hyper = "0.14.17" +loading = "0.3.0" axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/builder.rs b/src/builder.rs index 4feb87839..0dce6d71d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,7 +6,7 @@ use crate::{ }; use std::{ fs::{copy, create_dir_all, remove_dir_all, File}, - io::Read, + io::{Read, BufRead}, panic, path::PathBuf, process::Command, @@ -42,8 +42,9 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { .arg("build") .arg("--target") .arg("wasm32-unknown-unknown") - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()); + .arg("--message-format=json") + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()); if config.release { cmd.arg("--release"); @@ -74,7 +75,14 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; + let loading = loading::Loading::default(); + loading.text("Building"); let output = cmd.output()?; + for i in output.stdout.lines() { + // println!("{:?}", i); + } + loading.success("OK"); + loading.end(); if !output.status.success() { log::error!("Build failed!"); From 5edcb9238c33c253ca62831bbd8947d4e8b49c05 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Fri, 8 Jul 2022 09:26:05 +0800 Subject: [PATCH 167/895] feat: cargo format struct --- src/builder.rs | 26 ++++++++++++++++++-------- src/cargo.rs | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 0dce6d71d..a662f8a20 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -77,18 +77,28 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { let loading = loading::Loading::default(); loading.text("Building"); - let output = cmd.output()?; - for i in output.stdout.lines() { - // println!("{:?}", i); + let mut child = cmd.spawn()?; + let out = child.stdout.take().unwrap(); + let mut out = std::io::BufReader::new(out); + let mut s = String::new(); + let mut n = 0; + while let Ok(_) = out.read_line(&mut s) { + // 进程退出后结束循环 + if let Ok(Some(_)) = child.try_wait() { + break; + } + println!("\n{}\n", s); + loading.text(format!("Building {}", n)); + n += 1; } loading.success("OK"); loading.end(); - if !output.status.success() { - log::error!("Build failed!"); - let reason = String::from_utf8_lossy(&output.stderr).to_string(); - return Err(Error::BuildFailed(reason)); - } + // if !output.status.success() { + // log::error!("Build failed!"); + // let reason = String::from_utf8_lossy(&output.stderr).to_string(); + // return Err(Error::BuildFailed(reason)); + // } // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets").join("dioxus"); diff --git a/src/cargo.rs b/src/cargo.rs index 251e9d848..9994d5be5 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,4 +1,6 @@ //! Utilities for working with cargo and rust files +use serde::Serialize; + use crate::error::{Error, Result}; use std::{ env, fs, @@ -90,3 +92,26 @@ impl Metadata { Err(Error::CargoError("InvalidOutput".to_string())) } } + +#[derive(Serialize, Debug, Clone)] +pub struct CargoFormatInfo { + pub reason: CargoFormatReason, + #[serde(default)] + pub package_id: String, + #[serde(default)] + manifest_path: String, + #[serde(default)] + message: Option +} + +#[derive(Serialize, Debug, Clone)] +pub enum CargoFormatReason { + #[serde(rename = "compiler-message")] + CompilerMessage, + #[serde(rename = "compiler-artifact")] + CompilerArtifact, + #[serde(rename = "build-script-executed")] + BuildScriptExecuted, + #[serde(rename = "build-finished")] + BuildFinished, +} \ No newline at end of file From 0a2bac87154f8c867fc0427fabe21ce04fd3b026 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 00:28:00 +0800 Subject: [PATCH 168/895] feat: commit code --- src/builder.rs | 21 +++++++++++++-------- src/cargo.rs | 10 ++++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index a662f8a20..bdb82fc45 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2,11 +2,11 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, tools::Tool, - DioxusConfig, + CargoFormatInfo, DioxusConfig, }; use std::{ fs::{copy, create_dir_all, remove_dir_all, File}, - io::{Read, BufRead}, + io::{BufRead, Read}, panic, path::PathBuf, process::Command, @@ -80,16 +80,21 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { let mut child = cmd.spawn()?; let out = child.stdout.take().unwrap(); let mut out = std::io::BufReader::new(out); - let mut s = String::new(); - let mut n = 0; - while let Ok(_) = out.read_line(&mut s) { + let mut content = String::new(); + while let Ok(_) = out.read_line(&mut content) { // 进程退出后结束循环 if let Ok(Some(_)) = child.try_wait() { break; } - println!("\n{}\n", s); - loading.text(format!("Building {}", n)); - n += 1; + let content = content.split('\n').collect::>(); + for json in content { + let d = serde_json::from_str::(&json); + if let Ok(d) = d { + println!("\n{:#?}\n", d); + } else { + println!("\n\n{:?}\n\n", json); + } + } } loading.success("OK"); loading.end(); diff --git a/src/cargo.rs b/src/cargo.rs index 9994d5be5..6c5085066 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,5 +1,5 @@ //! Utilities for working with cargo and rust files -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crate::error::{Error, Result}; use std::{ @@ -93,7 +93,7 @@ impl Metadata { } } -#[derive(Serialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct CargoFormatInfo { pub reason: CargoFormatReason, #[serde(default)] @@ -101,10 +101,12 @@ pub struct CargoFormatInfo { #[serde(default)] manifest_path: String, #[serde(default)] - message: Option + target: Option, + #[serde(default)] + message: Option, } -#[derive(Serialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub enum CargoFormatReason { #[serde(rename = "compiler-message")] CompilerMessage, From eb0145173d0f8d5db715875d3213499172e89ea8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 00:32:23 +0800 Subject: [PATCH 169/895] feat: add `indicatif` crate --- Cargo.toml | 2 +- src/builder.rs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7e982bc78..a50a06fde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ regex = "1.5.4" chrono = "0.4.19" anyhow = "1.0.53" hyper = "0.14.17" -loading = "0.3.0" +indicatif = "0.16.2" axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/builder.rs b/src/builder.rs index bdb82fc45..ed0921cd1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -75,8 +75,6 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; - let loading = loading::Loading::default(); - loading.text("Building"); let mut child = cmd.spawn()?; let out = child.stdout.take().unwrap(); let mut out = std::io::BufReader::new(out); @@ -96,8 +94,6 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { } } } - loading.success("OK"); - loading.end(); // if !output.status.success() { // log::error!("Build failed!"); From dfe571df1a6260f31eff5f3e83113c448786e3b1 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 10:09:25 +0800 Subject: [PATCH 170/895] feat: commit prettier_build --- Cargo.toml | 2 +- src/builder.rs | 58 ++++++++++++++++++++++++++++++++------------------ src/cargo.rs | 27 ----------------------- 3 files changed, 38 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a50a06fde..7e982bc78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ regex = "1.5.4" chrono = "0.4.19" anyhow = "1.0.53" hyper = "0.14.17" -indicatif = "0.16.2" +loading = "0.3.0" axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/builder.rs b/src/builder.rs index ed0921cd1..5ef084326 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2,11 +2,14 @@ use crate::{ config::{CrateConfig, ExecutableType}, error::{Error, Result}, tools::Tool, - CargoFormatInfo, DioxusConfig, + DioxusConfig, }; +use cargo_metadata::Message; +use loading::Loading; use std::{ + collections::HashMap, fs::{copy, create_dir_all, remove_dir_all, File}, - io::{BufRead, Read}, + io::Read, panic, path::PathBuf, process::Command, @@ -75,25 +78,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; - let mut child = cmd.spawn()?; - let out = child.stdout.take().unwrap(); - let mut out = std::io::BufReader::new(out); - let mut content = String::new(); - while let Ok(_) = out.read_line(&mut content) { - // 进程退出后结束循环 - if let Ok(Some(_)) = child.try_wait() { - break; - } - let content = content.split('\n').collect::>(); - for json in content { - let d = serde_json::from_str::(&json); - if let Ok(d) = d { - println!("\n{:#?}\n", d); - } else { - println!("\n\n{:?}\n\n", json); - } - } - } + prettier_build(cmd).unwrap(); // if !output.status.success() { // log::error!("Build failed!"); @@ -342,6 +327,37 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { Ok(()) } +fn prettier_build(mut cmd: Command) -> anyhow::Result<()> { + let loading = Loading::default(); + let mut record: HashMap = HashMap::new(); + let mut command = cmd.spawn()?; + let reader = std::io::BufReader::new(command.stdout.take().unwrap()); + for message in cargo_metadata::Message::parse_stream(reader) { + match message.unwrap() { + Message::CompilerMessage(_msg) => { + // println!("{:#?}", msg); + } + Message::CompilerArtifact(artifact) => { + record.insert(artifact.package_id.to_string(), artifact.target.name); + } + Message::BuildScriptExecuted(script) => { + let package_id = script.package_id.to_string(); + if let Some(name) = record.get(&package_id) { + loading.text(format!("[{}] build done", name)); + } + } + Message::BuildFinished(finished) => { + if finished.success { + } else { + std::process::exit(1); + } + } + _ => (), // Unknown message + } + } + Ok(()) +} + pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let crate_root = crate::cargo::crate_root().unwrap(); let custom_html_file = crate_root.join("index.html"); diff --git a/src/cargo.rs b/src/cargo.rs index 6c5085066..251e9d848 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -1,6 +1,4 @@ //! Utilities for working with cargo and rust files -use serde::{Serialize, Deserialize}; - use crate::error::{Error, Result}; use std::{ env, fs, @@ -92,28 +90,3 @@ impl Metadata { Err(Error::CargoError("InvalidOutput".to_string())) } } - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CargoFormatInfo { - pub reason: CargoFormatReason, - #[serde(default)] - pub package_id: String, - #[serde(default)] - manifest_path: String, - #[serde(default)] - target: Option, - #[serde(default)] - message: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum CargoFormatReason { - #[serde(rename = "compiler-message")] - CompilerMessage, - #[serde(rename = "compiler-artifact")] - CompilerArtifact, - #[serde(rename = "build-script-executed")] - BuildScriptExecuted, - #[serde(rename = "build-finished")] - BuildFinished, -} \ No newline at end of file From 98134cfe1ce33d12ab1dcba2fa1ca71b05e8a682 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 10:09:44 +0800 Subject: [PATCH 171/895] feat: commit Cargo.lock --- .gitignore | 1 - Cargo.lock | 4684 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4684 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 2e049011e..6b39d31a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target -Cargo.lock .idea/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..086673b7a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4684 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-task" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atk" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +dependencies = [ + "atk-sys", + "bitflags", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2cc6e8e8c993cb61a005fab8c1e5093a29199b7253b05a6883999312935c1ff" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.13.0", + "bitflags", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sha-1 0.10.0", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-http 0.3.4", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4d047478b986f14a13edad31a009e2e05cb241f9805d0d75e4cba4e129ad4d" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "binary-install" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5bc5f8c50dd6a80d0b303ddab79f42ddcb52fd43d68107ecf622c551fd4cd4" +dependencies = [ + "curl", + "dirs 1.0.5", + "failure", + "flate2", + "hex", + "is_executable", + "siphasher", + "tar", + "zip 0.5.13", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "blocking" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cairo-rs" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.12", + "serde", + "serde_json", +] + +[[package]] +name = "cargo_toml" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5809dd3e6444651fd1cdd3dbec71eca438c439a0fcc8081674a14da0afe50185" +dependencies = [ + "serde", + "serde_derive", + "toml", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-expr" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.44", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "clap" +version = "3.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +dependencies = [ + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "colored" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "crypto-common" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999502d32b9c48d492abe66392408144895020ec4709e549e840799f3bb74c0" +dependencies = [ + "generic-array 0.14.5", + "typenum", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "curl" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.55+curl-7.83.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "dioxus" +version = "0.2.4" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", + "dioxus-core-macro", + "dioxus-desktop", + "dioxus-hooks", + "dioxus-html", + "dioxus-router", + "dioxus-rsx", + "dioxus-rsx-interpreter", + "dioxus-web", +] + +[[package]] +name = "dioxus-cli" +version = "0.1.5" +dependencies = [ + "anyhow", + "atty", + "axum", + "binary-install", + "cargo_metadata", + "cargo_toml", + "chrono", + "clap", + "colored 2.0.0", + "convert_case", + "dioxus", + "dirs 4.0.0", + "fern", + "flate2", + "fs_extra", + "futures", + "headers", + "html_parser", + "hyper", + "loading", + "log", + "notify", + "proc-macro2", + "regex", + "reqwest", + "serde", + "serde_json", + "syn", + "tar", + "thiserror", + "tokio", + "toml", + "tower", + "tower-http 0.2.5", + "walkdir", + "wasm-bindgen-cli-support", + "zip 0.6.2", +] + +[[package]] +name = "dioxus-core" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "backtrace", + "bumpalo", + "futures-channel", + "futures-util", + "fxhash", + "indexmap", + "log", + "longest-increasing-subsequence", + "once_cell", + "serde", + "slab", + "smallvec", +] + +[[package]] +name = "dioxus-core-macro" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-rsx", + "dioxus-rsx-interpreter", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dioxus-desktop" +version = "0.2.3" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "core-foundation", + "dioxus-core", + "dioxus-html", + "dioxus-interpreter-js", + "dioxus-rsx-interpreter", + "dunce", + "futures-channel", + "interprocess", + "log", + "mime_guess", + "serde", + "serde_json", + "thiserror", + "tokio", + "webbrowser", + "wry", +] + +[[package]] +name = "dioxus-hooks" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", + "futures-channel", + "log", +] + +[[package]] +name = "dioxus-html" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", + "enumset", + "euclid", + "keyboard-types", + "serde", + "serde_repr", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "dioxus-interpreter-js" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "dioxus-router" +version = "0.2.3" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "futures-channel", + "futures-util", + "log", + "rsx-prelude", + "serde", + "serde_urlencoded", + "thiserror", + "url", +] + +[[package]] +name = "dioxus-rsx" +version = "0.0.0" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dioxus-rsx-interpreter" +version = "0.1.0" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", + "dioxus-hooks", + "dioxus-html", + "dioxus-rsx", + "dioxus-ssr", + "lazy_static", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "dioxus-ssr" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", +] + +[[package]] +name = "dioxus-web" +version = "0.2.1" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "anyhow", + "console_error_panic_hook", + "dioxus-core", + "dioxus-html", + "dioxus-interpreter-js", + "dioxus-rsx-interpreter", + "futures-channel", + "futures-util", + "fxhash", + "gloo-timers", + "js-sys", + "log", + "once_cell", + "serde-wasm-bindgen", + "serde_json", + "smallstr", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users 0.3.5", + "winapi", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users 0.4.3", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dunce" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumset" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4799cdb24d48f1f8a7a98d06b7fde65a85a2d1e42b25a889f5406aa1fbefe074" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "euclid" +version = "0.22.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fern" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" +dependencies = [ + "colored 1.9.3", + "log", +] + +[[package]] +name = "field-offset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.13", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps 6.0.2", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps 6.0.2", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "gio" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.2", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" +dependencies = [ + "anyhow", + "heck 0.4.0", + "proc-macro-crate 1.1.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "gtk" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +dependencies = [ + "atk", + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps 6.0.2", +] + +[[package]] +name = "gtk3-macros" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" +dependencies = [ + "anyhow", + "proc-macro-crate 1.1.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "headers" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +dependencies = [ + "base64 0.13.0", + "bitflags", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1 0.10.0", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "html_parser" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec016cabcf7c9c48f9d5fdc6b03f273585bfce640a0f47a69552039e92b1959a" +dependencies = [ + "pest", + "pest_derive", + "serde", + "serde_derive", + "serde_json", + "thiserror", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "interprocess" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c58ec7fbda1df9a93f587b780659db3c99f61f4be27f9c82c9b37684ffd0366" +dependencies = [ + "blocking", + "cfg-if", + "futures", + "intmap", + "libc", + "once_cell", + "spinning", + "thiserror", + "winapi", +] + +[[package]] +name = "intmap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" + +[[package]] +name = "ipconfig" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" +dependencies = [ + "socket2", + "widestring", + "winapi", + "winreg 0.7.0", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "is_executable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" +dependencies = [ + "winapi", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "javascriptcore-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +dependencies = [ + "bitflags", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "jni" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keyboard-types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" +dependencies = [ + "bitflags", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kqueue" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libayatana-appindicator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0379d22a323947cb27b4dbe3b14fc1dcde07c9e9c3eca52ddf97ca0819c28cc4" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "log", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "loading" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "676420b03272176423578148eee61319e893422694f6d96a394841cb0901357f" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "longest-increasing-subsequence" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3648f3609716eb7dbf5f5b5d4b84fcd67dd4c34efcdb12e4a6c0929c2ac48349" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.4.0", + "ndk-context", + "ndk-macro 0.2.0", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-context", + "ndk-macro 0.3.0", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling 0.10.2", + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.4", + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "notify" +version = "5.0.0-pre.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7" +dependencies = [ + "bitflags", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "mio", + "serde", + "walkdir", + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.2", +] + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.13", + "smallvec", + "windows-sys", +] + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +dependencies = [ + "digest 0.10.3", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1 0.8.2", +] + +[[package]] +name = "pin-project" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.16", + "redox_syscall 0.1.57", + "rust-argon2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.7", + "redox_syscall 0.2.13", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "trust-dns-resolver", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg 0.10.1", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rsx-prelude" +version = "0.1.0" +source = "git+https://github.com/dioxuslabs/dioxus/#baaa1752d3ccd5918fc472b1071b95a12b019687" +dependencies = [ + "dioxus-core", + "dioxus-core-macro", + "dioxus-hooks", + "dioxus-html", + "dioxus-rsx-interpreter", +] + +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64 0.13.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +dependencies = [ + "base64 0.13.0", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfc62771e7b829b517cb213419236475f434fb480eddd76112ae182d274434a" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallstr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e922794d168678729ffc7e07182721a14219c65814e66e91b839a272fe5ae4f" +dependencies = [ + "smallvec", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soup2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +dependencies = [ + "bitflags", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spinning" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" +dependencies = [ + "lock_api", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" +dependencies = [ + "cfg-expr 0.10.3", + "heck 0.4.0", + "pkg-config", + "toml", + "version-compare 0.1.0", +] + +[[package]] +name = "tao" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df895eb66ff23d1824055114d6fbdd2c297bf70ad85349a4adaee0f8b2a860d1" +dependencies = [ + "bitflags", + "cairo-rs", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdk", + "gdk-pixbuf", + "gdk-sys", + "gdkx11-sys", + "gio", + "glib", + "glib-sys", + "gtk", + "instant", + "lazy_static", + "libayatana-appindicator", + "libc", + "log", + "ndk 0.4.0", + "ndk-glue 0.4.2", + "ndk-sys 0.2.2", + "objc", + "parking_lot 0.11.2", + "raw-window-handle", + "scopeguard", + "serde", + "tao-core-video-sys", + "unicode-segmentation", + "windows", + "windows_macros", + "x11-dl", +] + +[[package]] +name = "tao-core-video-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271450eb289cb4d8d0720c6ce70c72c8c858c93dd61fc625881616752e6b98f6" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "objc", +] + +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall 0.2.13", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trust-dns-proto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot 0.12.1", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" +dependencies = [ + "base64 0.13.0", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha-1 0.10.0", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + +[[package]] +name = "version-compare" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "walrus" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser 0.77.0", +] + +[[package]] +name = "walrus-macro" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-cli-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4016fbd42224de21aab2f009aeaec61067d278a298ba7f8f7f8d40fbffea0822" +dependencies = [ + "anyhow", + "base64 0.9.3", + "log", + "rustc-demangle", + "serde_json", + "tempfile", + "walrus", + "wasm-bindgen-externref-xform", + "wasm-bindgen-multi-value-xform", + "wasm-bindgen-shared", + "wasm-bindgen-threads-xform", + "wasm-bindgen-wasm-conventions", + "wasm-bindgen-wasm-interpreter", + "wit-text", + "wit-validator", + "wit-walrus", +] + +[[package]] +name = "wasm-bindgen-externref-xform" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f33c8e2d3f3b6f6647f982911eb4cb44998c8cca97a4fe7afc99f616ebb33a73" +dependencies = [ + "anyhow", + "walrus", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-multi-value-xform" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7015b54357604811162710d5cf274ab85d974fe1e324222dd5b2133afdefe9b9" +dependencies = [ + "anyhow", + "walrus", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "wasm-bindgen-threads-xform" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6961b838d9a9c121ba4a1eea1628014cc759469e3defb42bbac9c5ed0f65be14" +dependencies = [ + "anyhow", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasm-bindgen-wasm-conventions" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0a0eca38fe89471f57d6903f3e17e732d2d6f995a7af5b23f27df7fee0f0d18" +dependencies = [ + "anyhow", + "walrus", +] + +[[package]] +name = "wasm-bindgen-wasm-interpreter" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1c9fb7f71137840932bbb853ef1f83d68c88584b716c9bbae38675c9fb8b86" +dependencies = [ + "anyhow", + "log", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasmparser" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" + +[[package]] +name = "wasmparser" +version = "0.77.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6" + +[[package]] +name = "wast" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1844f66a2bc8526d71690104c0e78a8e59ffa1597b7245769d174ebb91deb5" +dependencies = [ + "leb128", +] + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b" +dependencies = [ + "jni 0.19.0", + "ndk-glue 0.6.2", + "url", + "web-sys", + "widestring", + "winapi", +] + +[[package]] +name = "webkit2gtk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29952969fb5e10fe834a52eb29ad0814ccdfd8387159b0933edf1344a1c9cdcc" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup2", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +dependencies = [ + "atk-sys", + "bitflags", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pango-sys", + "pkg-config", + "soup2-sys", + "system-deps 6.0.2", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d8de8415c823c8abd270ad483c6feeac771fad964890779f9a8cb24fbbc1bf" +dependencies = [ + "webpki", +] + +[[package]] +name = "webview2-com" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb8e90ac2d9ce39cdb70017aaec641be09fbdd702b7b332b9896d053eb469524" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows_macros", +] + +[[package]] +name = "webview2-com-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515c6c82fcee93f6edaacc72c8e233dbe4ff3ca569dce1901dfc36c404a3e99" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "webview2-com-sys" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92160310b3322397e4ff8a8285a7429d73a07a68fda44ee80879605b93e53f76" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror", + "windows", + "windows-bindgen", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" +dependencies = [ + "windows_aarch64_msvc 0.30.0", + "windows_i686_gnu 0.30.0", + "windows_i686_msvc 0.30.0", + "windows_x86_64_gnu 0.30.0", + "windows_x86_64_msvc 0.30.0", +] + +[[package]] +name = "windows-bindgen" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944c545fcae9dd66488308f8b69aa3ba34f53714416ecfcdcbbfa4b6821e27c6" +dependencies = [ + "windows_quote", + "windows_reader", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_gen" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30dff4d91d22520628bb94b66f2bb313cb16a09a515a32320a84a1b449bc94c0" +dependencies = [ + "windows_quote", + "windows_reader", +] + +[[package]] +name = "windows_i686_gnu" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_macros" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ae44ab917e9005fe710d99d52d227ca0164b10a09be90649142cc3fab825d3" +dependencies = [ + "syn", + "windows_gen", + "windows_quote", + "windows_reader", +] + +[[package]] +name = "windows_quote" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f02c51a77e6248c1206aaa920802c32d50a05205e229b118d7f3afd3036667" + +[[package]] +name = "windows_reader" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44e6df0da993cda589c5ac852272fbb2a0ead67a031a017dd3eac11528a2d72" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "wit-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f5fd97866f4b9c8e1ed57bcf9446f3d0d8ba37e2dd01c3c612c046c053b06f7" +dependencies = [ + "anyhow", + "leb128", + "wit-schema-version", +] + +[[package]] +name = "wit-schema-version" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfee4a6a4716eefa0682e7a3b836152e894a3e4f34a9d6c2c3e1c94429bfe36a" + +[[package]] +name = "wit-text" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33358e95c77d660f1c7c07f4a93c2bd89768965e844e3c50730bb4b42658df5f" +dependencies = [ + "anyhow", + "wast", + "wit-writer", +] + +[[package]] +name = "wit-validator" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c11d93d925420e7872b226c4161849c32be38385ccab026b88df99d8ddc6ba6" +dependencies = [ + "anyhow", + "wasmparser 0.59.0", + "wit-parser", + "wit-schema-version", +] + +[[package]] +name = "wit-walrus" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad559e3e4c6404b2a6a675d44129d62a3836e3b951b90112fa1c5feb852757cd" +dependencies = [ + "anyhow", + "id-arena", + "walrus", + "wit-parser", + "wit-schema-version", + "wit-writer", +] + +[[package]] +name = "wit-writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad01ba5e9cbcff799a0689e56a153776ea694cec777f605938cb9880d41a09" +dependencies = [ + "leb128", + "wit-schema-version", +] + +[[package]] +name = "wry" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5676092e1a33448ed0f268717bcbb2e928354b78f4c1f60f3d43641eedea0d9" +dependencies = [ + "block", + "cocoa", + "core-graphics", + "gdk", + "gio", + "glib", + "gtk", + "http", + "jni 0.18.0", + "libc", + "log", + "objc", + "objc_id", + "once_cell", + "serde", + "serde_json", + "tao", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows_macros", +] + +[[package]] +name = "x11" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", + "time 0.1.44", +] + +[[package]] +name = "zip" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time 0.3.11", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.10.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.6+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +dependencies = [ + "cc", + "libc", +] From 526a88cab16045cf6b8acba75471cc62f17dca10 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 14:16:19 +0800 Subject: [PATCH 172/895] feat: commit code --- Cargo.lock | 66 +++++++++++++++++++++++++++++----- Cargo.toml | 4 +-- src/builder.rs | 73 +++++++++++++++++++++++-------------- src/cli/serve/mod.rs | 36 ++++++++----------- src/server/mod.rs | 86 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 190 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 086673b7a..4c4720564 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" dependencies = [ "camino", "cargo-platform", @@ -590,6 +590,21 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "console" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -872,7 +887,7 @@ dependencies = [ "headers", "html_parser", "hyper", - "loading", + "indicatif", "log", "notify", "proc-macro2", @@ -1101,6 +1116,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.31" @@ -1906,6 +1927,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017d0ce94b8e91e29d2c78ed891e57e5ec3dc4371820a9d96abab4af09eb8ad" +dependencies = [ + "console", + "number_prefix", + "unicode-width", +] + [[package]] name = "inotify" version = "0.9.6" @@ -2145,12 +2177,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "loading" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "676420b03272176423578148eee61319e893422694f6d96a394841cb0901357f" - [[package]] name = "lock_api" version = "0.4.7" @@ -2469,6 +2495,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "objc" version = "0.2.7" @@ -3525,6 +3557,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "textwrap" version = "0.15.0" @@ -3893,6 +3935,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 7e982bc78..da2467fc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,14 +29,14 @@ notify = { version = "5.0.0-pre.13", features = ["serde"] } html_parser = "0.6.2" binary-install = "0.0.2" convert_case = "0.5.0" -cargo_metadata = "0.14.1" +cargo_metadata = "0.15.0" tokio = { version = "1.16.1", features = ["full"] } atty = "0.2.14" regex = "1.5.4" chrono = "0.4.19" anyhow = "1.0.53" hyper = "0.14.17" -loading = "0.3.0" +indicatif = "0.17.0-rc.11" axum = { version = "0.5.1", features = ["ws", "headers"] } tower-http = { version = "0.2.2", features = ["fs", "trace"] } diff --git a/src/builder.rs b/src/builder.rs index 5ef084326..d164e5418 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,19 +4,26 @@ use crate::{ tools::Tool, DioxusConfig, }; -use cargo_metadata::Message; -use loading::Loading; +use cargo_metadata::{diagnostic::Diagnostic, Message}; +use indicatif::{ProgressBar, ProgressStyle}; +use serde::Serialize; use std::{ - collections::HashMap, fs::{copy, create_dir_all, remove_dir_all, File}, io::Read, panic, path::PathBuf, process::Command, + time::Duration, }; use wasm_bindgen_cli_support::Bindgen; -pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { +#[derive(Serialize, Debug, Clone)] +pub struct BuildResult { + pub warnings: Vec, + pub elapsed_time: u128, +} + +pub fn build(config: &CrateConfig, quiet: bool) -> Result { // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?) // [2] Generate the appropriate build folders // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm @@ -78,13 +85,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; - prettier_build(cmd).unwrap(); - - // if !output.status.success() { - // log::error!("Build failed!"); - // let reason = String::from_utf8_lossy(&output.stderr).to_string(); - // return Err(Error::BuildFailed(reason)); - // } + let warning_messages = prettier_build(cmd)?; // [2] Establish the output directory structure let bindgen_outdir = out_dir.join("assets").join("dioxus"); @@ -122,8 +123,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { .unwrap(); }); if bindgen_result.is_err() { - log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate."); - return Ok(()); + return Err(Error::BuildFailed("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate.".to_string())); } // check binaryen:wasm-opt tool @@ -193,8 +193,10 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<()> { } let t_end = std::time::Instant::now(); - log::info!("🏁 Done in {}ms!", (t_end - t_start).as_millis()); - Ok(()) + Ok(BuildResult { + warnings: warning_messages, + elapsed_time: (t_end - t_start).as_millis() + }) } pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { @@ -327,27 +329,46 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> { Ok(()) } -fn prettier_build(mut cmd: Command) -> anyhow::Result<()> { - let loading = Loading::default(); - let mut record: HashMap = HashMap::new(); +fn prettier_build(mut cmd: Command) -> anyhow::Result> { + let mut warning_messages: Vec = vec![]; + + let pb = ProgressBar::new_spinner(); + pb.enable_steady_tick(Duration::from_millis(200)); + pb.set_style( + ProgressStyle::with_template("{spinner:.dim.bold} {wide_msg}") + .unwrap() + .tick_chars("/|\\- "), + ); + pb.set_message("Start to build project"); + let mut command = cmd.spawn()?; let reader = std::io::BufReader::new(command.stdout.take().unwrap()); for message in cargo_metadata::Message::parse_stream(reader) { match message.unwrap() { - Message::CompilerMessage(_msg) => { - // println!("{:#?}", msg); + Message::CompilerMessage(msg) => { + let message = msg.message; + match message.level { + cargo_metadata::diagnostic::DiagnosticLevel::Error => { + log::error!("Build Failed: {}", message.message); + std::process::exit(1); + } + cargo_metadata::diagnostic::DiagnosticLevel::Warning => { + warning_messages.push(message.clone()); + } + _ => {} + } } Message::CompilerArtifact(artifact) => { - record.insert(artifact.package_id.to_string(), artifact.target.name); + pb.set_message(format!("Compiling {} ", artifact.package_id)); + pb.tick(); } Message::BuildScriptExecuted(script) => { - let package_id = script.package_id.to_string(); - if let Some(name) = record.get(&package_id) { - loading.text(format!("[{}] build done", name)); - } + let _package_id = script.package_id.to_string(); } Message::BuildFinished(finished) => { if finished.success { + pb.finish_and_clear(); + println!("Done in"); } else { std::process::exit(1); } @@ -355,7 +376,7 @@ fn prettier_build(mut cmd: Command) -> anyhow::Result<()> { _ => (), // Unknown message } } - Ok(()) + Ok(warning_messages) } pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 62843d653..93770b6ed 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -38,31 +38,25 @@ impl Serve { .clone() }); - match platform.as_str() { - "web" => { - crate::builder::build(&crate_config, false)?; - } - "desktop" => { - crate::builder::build_desktop(&crate_config, true)?; + if platform.as_str() == "desktop" { + crate::builder::build_desktop(&crate_config, true)?; - match &crate_config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) - | crate::ExecutableType::Example(name) => { - let mut file = crate_config.out_dir.join(name); - if cfg!(windows) { - file.set_extension("exe"); - } - Command::new(crate_config.out_dir.join(file).to_str().unwrap()) - .stdout(Stdio::inherit()) - .output()?; + match &crate_config.executable { + crate::ExecutableType::Binary(name) + | crate::ExecutableType::Lib(name) + | crate::ExecutableType::Example(name) => { + let mut file = crate_config.out_dir.join(name); + if cfg!(windows) { + file.set_extension("exe"); } + Command::new(crate_config.out_dir.join(file).to_str().unwrap()) + .stdout(Stdio::inherit()) + .output()?; } - return Ok(()); - } - _ => { - return custom_error!("Unsoppurt platform target."); } + return Ok(()); + } else if platform != "web" { + return custom_error!("Unsoppurt platform target."); } // generate dev-index page diff --git a/src/server/mod.rs b/src/server/mod.rs index 3ecce6c26..b20d84db3 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,6 +6,7 @@ use axum::{ routing::{get, get_service}, Router, }; +use cargo_metadata::diagnostic::Diagnostic; use colored::Colorize; use dioxus::rsx_interpreter::SetRsxMessage; use notify::{RecommendedWatcher, Watcher}; @@ -15,7 +16,7 @@ use std::{net::UdpSocket, path::PathBuf, process::Command, sync::Arc}; use tower::ServiceBuilder; use tower_http::services::fs::{ServeDir, ServeFileSystemResponseBody}; -use crate::{builder, serve::Serve, CrateConfig, Result}; +use crate::{builder, serve::Serve, BuildResult, CrateConfig, Result}; use tokio::sync::broadcast; mod hot_reload; @@ -27,9 +28,9 @@ pub struct BuildManager { } impl BuildManager { - fn rebuild(&self) -> Result<()> { + fn rebuild(&self) -> Result { log::info!("🪁 Rebuild project"); - builder::build(&self.config, true)?; + let result = builder::build(&self.config, true)?; // change the websocket reload state to true; // the page will auto-reload. if self @@ -43,7 +44,7 @@ impl BuildManager { let _ = Serve::regen_dev_page(&self.config); } let _ = self.reload_tx.send(()); - Ok(()) + Ok(result) } } @@ -61,6 +62,8 @@ pub async fn startup(port: u16, config: CrateConfig) -> Result<()> { } pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { + let first_build_result = crate::builder::build(&config, false)?; + log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -159,9 +162,22 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } } if needs_rebuild { - print_console_info(port, &config, evt.paths); - if let Err(err) = build_manager.rebuild() { - log::error!("{}", err); + match build_manager.rebuild() { + Ok(res) => { + print_console_info( + port, + &config, + PrettierOptions { + changed: evt.paths, + warnings: res.warnings, + elapsed_time: res.elapsed_time, + }, + ); + } + Err(err) => { + log::error!("{}", err); + std::process::exit(1); + } } } if !messages.is_empty() { @@ -183,7 +199,15 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0:8080 - print_console_info(port, &config, vec![]); + print_console_info( + port, + &config, + PrettierOptions { + changed: vec![], + warnings: first_build_result.warnings, + elapsed_time: first_build_result.elapsed_time, + }, + ); let file_service_config = config.clone(); let file_service = ServiceBuilder::new() @@ -246,6 +270,8 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { + let first_build_result = crate::builder::build(&config, false)?; + log::info!("🚀 Starting development server..."); let dist_path = config.out_dir.clone(); @@ -276,10 +302,20 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { let mut watcher = RecommendedWatcher::new(move |info: notify::Result| { let config = watcher_config.clone(); if info.is_ok() { - print_console_info(port, &config, info.unwrap().paths); if chrono::Local::now().timestamp() > last_update_time { match build_manager.rebuild() { - Ok(_) => last_update_time = chrono::Local::now().timestamp(), + Ok(res) => { + last_update_time = chrono::Local::now().timestamp(); + print_console_info( + port, + &config, + PrettierOptions { + changed: info.unwrap().paths, + warnings: res.warnings, + elapsed_time: res.elapsed_time, + }, + ); + } Err(e) => log::error!("{}", e), } } @@ -297,8 +333,16 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { } // start serve dev-server at 0.0.0.0 - print_console_info(port, &config, vec![]); - + print_console_info( + port, + &config, + PrettierOptions { + changed: vec![], + warnings: first_build_result.warnings, + elapsed_time: first_build_result.elapsed_time, + }, + ); + let file_service_config = config.clone(); let file_service = ServiceBuilder::new() .and_then( @@ -355,7 +399,14 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { Ok(()) } -fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { +#[derive(Debug, Default)] +pub struct PrettierOptions { + changed: Vec, + warnings: Vec, + elapsed_time: u128, +} + +fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) { print!( "{}", String::from_utf8_lossy( @@ -413,7 +464,7 @@ fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { "False" }; - if changed.len() <= 0 { + if options.changed.len() <= 0 { println!( "{} @ v{}\n", "Dioxus".bold().green(), @@ -422,7 +473,9 @@ fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { } else { println!( "Project Reloaded: {}\n", - format!("Changed {} files.", changed.len()).purple().bold() + format!("Changed {} files.", options.changed.len()) + .purple() + .bold() ); } println!( @@ -446,12 +499,11 @@ fn print_console_info(port: u16, config: &CrateConfig, changed: Vec) { println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple()); println!(""); - if changed.len() <= 0 { + if options.changed.len() <= 0 { log::info!("{}", "Server startup completed.".green().bold()); } else { log::info!("{}", "Project rebuild completed.".green().bold()); } - } fn get_ip() -> Option { From 78c78548e80c1be44589409f3b99f065aa77c781 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 16:41:53 +0800 Subject: [PATCH 173/895] feat: commit prettier_build --- src/builder.rs | 2 +- src/server/mod.rs | 42 +++++++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index d164e5418..33ce411f6 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -368,7 +368,7 @@ fn prettier_build(mut cmd: Command) -> anyhow::Result> { Message::BuildFinished(finished) => { if finished.success { pb.finish_and_clear(); - println!("Done in"); + log::info!("Build done."); } else { std::process::exit(1); } diff --git a/src/server/mod.rs b/src/server/mod.rs index b20d84db3..5cd5cdcb7 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -342,7 +342,7 @@ pub async fn startup_default(port: u16, config: CrateConfig) -> Result<()> { elapsed_time: first_build_result.elapsed_time, }, ); - + let file_service_config = config.clone(); let file_service = ServiceBuilder::new() .and_then( @@ -434,18 +434,6 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) profile = config.custom_profile.as_ref().unwrap().to_string(); } let hot_reload = if config.hot_reload { "RSX" } else { "Normal" }; - let tools_str = format!( - "{:?}", - config - .dioxus_config - .application - .tools - .clone() - .unwrap_or_default() - .iter() - .map(|d| d.0.clone()) - .collect::>() - ); let crate_root = crate::cargo::crate_root().unwrap(); let custom_html_file = if crate_root.join("index.html").is_file() { "Custom [index.html]" @@ -494,15 +482,35 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) println!(""); println!("\t> Profile : {}", profile.green()); println!("\t> Hot Reload : {}", hot_reload.cyan()); - println!("\t> Enabled Tools : {}", tools_str.yellow()); println!("\t> Index Template : {}", custom_html_file.green()); println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple()); println!(""); + println!( + "\t> Build Time Use : {} millis", + options.elapsed_time.to_string().green().bold() + ); + println!(""); - if options.changed.len() <= 0 { - log::info!("{}", "Server startup completed.".green().bold()); + if options.warnings.len() == 0 { + log::info!("{}\n", "A perfect compilation!".green().bold()); } else { - log::info!("{}", "Project rebuild completed.".green().bold()); + log::warn!( + "{}\n", + format!( + "There were {} warning messages during the build: ", + options.warnings.len() - 1 + ) + .yellow() + .bold() + ); + for info in &options.warnings { + if info.message == format!("{} warnings emitted", options.warnings.len() - 1) { + continue; + } + if let Some(val) = info.rendered.clone() { + log::warn!("{}", val); + } + } } } From 8613518c40e722f5e9abfbb53ed7df034ab2b7a3 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 20:00:17 +0800 Subject: [PATCH 174/895] feat: commit code --- src/server/mod.rs | 58 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 5cd5cdcb7..614e8fa7a 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -495,7 +495,7 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) log::info!("{}\n", "A perfect compilation!".green().bold()); } else { log::warn!( - "{}\n", + "{}", format!( "There were {} warning messages during the build: ", options.warnings.len() - 1 @@ -504,13 +504,63 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) .bold() ); for info in &options.warnings { - if info.message == format!("{} warnings emitted", options.warnings.len() - 1) { + let message = info.message.clone(); + if message == format!("{} warnings emitted", options.warnings.len() - 1) { continue; } - if let Some(val) = info.rendered.clone() { - log::warn!("{}", val); + let mut console = String::new(); + for span in &info.spans { + let file = &span.file_name; + let line = (span.line_start, span.line_end); + let line_str = if line.0 == line.1 { + line.0.to_string() + } else { + format!("{}~{}", line.0, line.1) + }; + let code = span.text.clone(); + // let span_info = format!( + // "[{}: {}]: {} --> {}", + // file, + // if line.0 == line.1 { + // line.0.to_string() + // } else { + // format!("{}~{}", line.0, line.1) + // }, + // if code.len() == 1 { + // code.get(0).unwrap().text.trim().blue().bold().to_string() + // } else { + // format!("\n{}",code.iter() + // .enumerate() + // .map(|(_i, s)| format!("\t{}\n", s.text).blue().bold().to_string()) + // .collect::()) + // }, + // message.yellow().bold() + // ); + let span_info = if code.len() == 1 { + let code = code.get(0).unwrap().text.trim().blue().bold().to_string(); + format!( + "[{}: {}]: '{}' --> {}", + file, + line_str, + code, + message.yellow().bold() + ) + } else { + let code = code + .iter() + .enumerate() + .map(|(_i, s)| format!("\t{}\n", s.text).blue().bold().to_string()) + .collect::(); + format!("[{}: {}]:\n{}", file, line_str, code) + }; + console = format!("{console}\n\t{span_info}"); } + println!("{console}"); } + println!( + "\n{}\n", + "Resolving all warnings will help your code run better!".yellow() + ); } } From bfaa8e3c74aa82d2ad6a5b917af98f9e6cc729f8 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 20:54:16 +0800 Subject: [PATCH 175/895] feat: commit code --- src/server/mod.rs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 614e8fa7a..e5bffc17e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -518,24 +518,6 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) format!("{}~{}", line.0, line.1) }; let code = span.text.clone(); - // let span_info = format!( - // "[{}: {}]: {} --> {}", - // file, - // if line.0 == line.1 { - // line.0.to_string() - // } else { - // format!("{}~{}", line.0, line.1) - // }, - // if code.len() == 1 { - // code.get(0).unwrap().text.trim().blue().bold().to_string() - // } else { - // format!("\n{}",code.iter() - // .enumerate() - // .map(|(_i, s)| format!("\t{}\n", s.text).blue().bold().to_string()) - // .collect::()) - // }, - // message.yellow().bold() - // ); let span_info = if code.len() == 1 { let code = code.get(0).unwrap().text.trim().blue().bold().to_string(); format!( @@ -551,7 +533,7 @@ fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) .enumerate() .map(|(_i, s)| format!("\t{}\n", s.text).blue().bold().to_string()) .collect::(); - format!("[{}: {}]:\n{}", file, line_str, code) + format!("[{}: {}]:\n{}\n#:{}", file, line_str, code, message) }; console = format!("{console}\n\t{span_info}"); } From d543ea19d0f2647a795b1cd32c243f0591e5f8f1 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 22:02:33 +0800 Subject: [PATCH 176/895] feat: commit some thing --- src/builder.rs | 9 ++++----- src/main.rs | 10 +++++----- src/server/mod.rs | 1 - 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 33ce411f6..31b99b5f4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -195,7 +195,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { let t_end = std::time::Instant::now(); Ok(BuildResult { warnings: warning_messages, - elapsed_time: (t_end - t_start).as_millis() + elapsed_time: (t_end - t_start).as_millis(), }) } @@ -339,7 +339,7 @@ fn prettier_build(mut cmd: Command) -> anyhow::Result> { .unwrap() .tick_chars("/|\\- "), ); - pb.set_message("Start to build project"); + pb.set_message("💼 Waiting to strart build the project..."); let mut command = cmd.spawn()?; let reader = std::io::BufReader::new(command.stdout.take().unwrap()); @@ -349,8 +349,7 @@ fn prettier_build(mut cmd: Command) -> anyhow::Result> { let message = msg.message; match message.level { cargo_metadata::diagnostic::DiagnosticLevel::Error => { - log::error!("Build Failed: {}", message.message); - std::process::exit(1); + return Err(anyhow::anyhow!(message.rendered.unwrap_or("Unknown".into()))); } cargo_metadata::diagnostic::DiagnosticLevel::Warning => { warning_messages.push(message.clone()); @@ -368,7 +367,7 @@ fn prettier_build(mut cmd: Command) -> anyhow::Result> { Message::BuildFinished(finished) => { if finished.success { pb.finish_and_clear(); - log::info!("Build done."); + log::info!("👑 Build done."); } else { std::process::exit(1); } diff --git a/src/main.rs b/src/main.rs index 099ff74c0..39b360f7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,31 +9,31 @@ async fn main() -> Result<()> { match args.action { Commands::Translate(opts) => { if let Err(e) = opts.translate() { - log::error!("translate error: {}", e); + log::error!("🚫 Translate failed: {}", e); } } Commands::Build(opts) => { if let Err(e) = opts.build() { - log::error!("build error: {}", e); + log::error!("🚫 Build project failed: {}", e); } } Commands::Clean(opts) => { if let Err(e) = opts.clean() { - log::error!("clean error: {}", e); + log::error!("🚫 Clean project failed: {}", e); } } Commands::Serve(opts) => { if let Err(e) = opts.serve().await { - log::error!("serve error: {}", e); + log::error!("🚫 Serve startup failed: {}", e); } } Commands::Create(opts) => { if let Err(e) = opts.create() { - log::error!("create error: {}", e); + log::error!("🚫 Create project failed: {}", e); } } diff --git a/src/server/mod.rs b/src/server/mod.rs index e5bffc17e..8f50a6cc3 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -176,7 +176,6 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> { } Err(err) => { log::error!("{}", err); - std::process::exit(1); } } } From dfcf4e1f88e6f8296a5691e13bd6a5122c64996d Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 22:17:32 +0800 Subject: [PATCH 177/895] feat: change default config --- README.md | 2 +- src/assets/dioxus.toml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a939dfcaf..f8515f390 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-

📦✨ dioxus-cli

+

📦✨ Dioxus CLI

Tooling to supercharge dioxus projects

diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index a5e849bfb..5c4f49f98 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -19,6 +19,8 @@ asset_dir = "public" # HTML title tag content title = "dioxus | ⛺" +index_on_404 = true + [web.watcher] watch_path = ["src"] @@ -45,10 +47,12 @@ script = [] binaryen = { wasm_opt = true } # use sass auto will auto check sass file and build it. -[application.tools.sass] + + +# [application.tools.sass] # auto will check the assets dirs, and auto to transform all scss file to css file. -input = "*" +# input = "*" # or you can specify some scss file -> css file # input = [ @@ -57,4 +61,4 @@ input = "*" # "/css/test.scss" # ] -source_map = true \ No newline at end of file +# source_map = true \ No newline at end of file From c97d7f263a4e785db533f726c80aee548d6f1cc0 Mon Sep 17 00:00:00 2001 From: YuKun Liu <41265098+mrxiaozhuox@users.noreply.github.com> Date: Sat, 9 Jul 2022 22:21:21 +0800 Subject: [PATCH 178/895] feat: commit code --- src/assets/dioxus.toml | 2 +- src/assets/index.html | 5 ++--- src/cli/create/mod.rs | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/dioxus.toml b/src/assets/dioxus.toml index 5c4f49f98..649aa2c3c 100644 --- a/src/assets/dioxus.toml +++ b/src/assets/dioxus.toml @@ -17,7 +17,7 @@ asset_dir = "public" [web.app] # HTML title tag content -title = "dioxus | ⛺" +title = "Dioxus | An elegant GUI library for Rust" index_on_404 = true diff --git a/src/assets/index.html b/src/assets/index.html index 87d447816..ed3d48135 100644 --- a/src/assets/index.html +++ b/src/assets/index.html @@ -9,10 +9,9 @@
- ".to_string()), + dioxus_desktop::Config::new() + .with_custom_head(r#""#.to_string()), ); + #[cfg(target_arch = "wasm32")] + dioxus_web::launch(app); } pub fn app(cx: Scope) -> Element { diff --git a/examples/tailwind/tailwind.config.js b/examples/tailwind/tailwind.config.js new file mode 100644 index 000000000..2a69d5803 --- /dev/null +++ b/examples/tailwind/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + mode: "all", + content: ["./src/**/*.{rs,html,css}", "./dist/**/*.html"], + theme: { + extend: {}, + }, + plugins: [], +}; From 7f6f6fb8c87d050d30e39d0bc2cf248d9996226e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 28 Mar 2023 13:35:17 -0500 Subject: [PATCH 364/895] create server package --- Cargo.toml | 1 + packages/server/Cargo.toml | 21 +++++ packages/server/server_macro/Cargo.toml | 8 ++ packages/server/server_macro/src/lib.rs | 67 +++++++++++++++ packages/server/src/adapters/axum_adapter.rs | 23 +++++ packages/server/src/adapters/salvo_adapter.rs | 25 ++++++ packages/server/src/adapters/warp_adapter.rs | 28 ++++++ packages/server/src/lib.rs | 85 +++++++++++++++++++ 8 files changed, 258 insertions(+) create mode 100644 packages/server/Cargo.toml create mode 100644 packages/server/server_macro/Cargo.toml create mode 100644 packages/server/server_macro/src/lib.rs create mode 100644 packages/server/src/adapters/axum_adapter.rs create mode 100644 packages/server/src/adapters/salvo_adapter.rs create mode 100644 packages/server/src/adapters/warp_adapter.rs create mode 100644 packages/server/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e32940e18..3b36bb5e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ members = [ "packages/rsx-rosetta", "packages/signals", "packages/hot-reload", + "packages/server", "docs/guide", ] diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml new file mode 100644 index 000000000..13704574b --- /dev/null +++ b/packages/server/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +server_fn = { version = "0.2.4", features = ["stable"] } + +# warp +warp = { version = "0.3.3", optional = true } + +# axum +axum = { version = "0.6.1", optional = true, features = ["ws"] } + +# salvo +salvo = { version = "0.37.7", optional = true, features = ["ws"] } +serde = "1.0.159" + +dioxus = { path = "../dioxus", version = "^0.3.0" } \ No newline at end of file diff --git a/packages/server/server_macro/Cargo.toml b/packages/server/server_macro/Cargo.toml new file mode 100644 index 000000000..6e8c69b46 --- /dev/null +++ b/packages/server/server_macro/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "server_macro" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/packages/server/server_macro/src/lib.rs b/packages/server/server_macro/src/lib.rs new file mode 100644 index 000000000..439a9e7b2 --- /dev/null +++ b/packages/server/server_macro/src/lib.rs @@ -0,0 +1,67 @@ +/// Declares that a function is a [server function](leptos_server). This means that +/// its body will only run on the server, i.e., when the `ssr` feature is enabled. +/// +/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features +/// 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 +/// (e.g., `MyServerFn`). +/// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered +/// (e.g., `"/api"`). Defaults to `"/"`. +/// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for +/// serialization) or `"Url"` (specifying that it should be use a URL-encoded form-data string). +/// Defaults to `"Url"`. If you want to use this server function to power a `
` that will +/// work without WebAssembly, the encoding must be `"Url"`. +/// +/// The server function itself can take any number of arguments, each of which should be serializable +/// and deserializable with `serde`. Optionally, its first argument can be a Leptos [Scope](leptos_reactive::Scope), +/// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other +/// server-side context into the server function. +/// +/// ```ignore +/// # use leptos::*; use serde::{Serialize, Deserialize}; +/// # #[derive(Serialize, Deserialize)] +/// # pub struct Post { } +/// #[server(ReadPosts, "/api")] +/// pub async fn read_posts(how_many: u8, query: String) -> Result, ServerFnError> { +/// // do some work on the server to access the database +/// todo!() +/// } +/// ``` +/// +/// Note the following: +/// - You must **register** the server function by calling `T::register()` somewhere in your main function. +/// - **Server functions must be `async`.** Even if the work being done inside the function body +/// can run synchronously on the server, from the client’s perspective it involves an asynchronous +/// function call. +/// - **Server functions must return `Result`.** Even if the work being done +/// inside the function body can’t fail, the processes of serialization/deserialization and the +/// network call are fallible. +/// - **Return types must be [Serializable](leptos_reactive::Serializable).** +/// This should be fairly obvious: we have to serialize arguments to send them to the server, and we +/// need to deserialize the result to return it to the client. +/// - **Arguments must be implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) +/// and [`DeserializeOwned`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html).** +/// They are serialized as an `application/x-www-form-urlencoded` +/// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor` +/// using [`cbor`](https://docs.rs/cbor/latest/cbor/). +/// - **The [Scope](leptos_reactive::Scope) comes from the server.** Optionally, the first argument of a server function +/// can be a Leptos [Scope](leptos_reactive::Scope). This scope can be used to inject dependencies like the HTTP request +/// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client. +#[proc_macro_attribute] +pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { + let context = ServerContext { + ty: syn::parse_quote!(Scope), + path: syn::parse_quote!(::leptos::Scope), + }; + match server_macro_impl( + args.into(), + s.into(), + Some(context), + Some(syn::parse_quote!(::leptos::server_fn)), + ) { + Err(e) => e.to_compile_error().into(), + Ok(s) => s.to_token_stream().into(), + } +} diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs new file mode 100644 index 000000000..646cde38e --- /dev/null +++ b/packages/server/src/adapters/axum_adapter.rs @@ -0,0 +1,23 @@ +use crate::{LiveViewError, LiveViewSocket}; +use axum::extract::ws::{Message, WebSocket}; +use futures_util::{SinkExt, StreamExt}; + +/// Convert a warp websocket into a LiveViewSocket +/// +/// This is required to launch a LiveView app using the warp web framework +pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket { + ws.map(transform_rx) + .with(transform_tx) + .sink_map_err(|_| LiveViewError::SendingFailed) +} + +fn transform_rx(message: Result) -> Result { + message + .map_err(|_| LiveViewError::SendingFailed)? + .into_text() + .map_err(|_| LiveViewError::SendingFailed) +} + +async fn transform_tx(message: String) -> Result { + Ok(Message::Text(message)) +} diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs new file mode 100644 index 000000000..2c8912a57 --- /dev/null +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -0,0 +1,25 @@ +use futures_util::{SinkExt, StreamExt}; +use salvo::ws::{Message, WebSocket}; + +use crate::{LiveViewError, LiveViewSocket}; + +/// Convert a salvo websocket into a LiveViewSocket +/// +/// This is required to launch a LiveView app using the warp web framework +pub fn salvo_socket(ws: WebSocket) -> impl LiveViewSocket { + ws.map(transform_rx) + .with(transform_tx) + .sink_map_err(|_| LiveViewError::SendingFailed) +} + +fn transform_rx(message: Result) -> Result { + let as_bytes = message.map_err(|_| LiveViewError::SendingFailed)?; + + let msg = String::from_utf8(as_bytes.into_bytes()).map_err(|_| LiveViewError::SendingFailed)?; + + Ok(msg) +} + +async fn transform_tx(message: String) -> Result { + Ok(Message::text(message)) +} diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs new file mode 100644 index 000000000..e5c821ce3 --- /dev/null +++ b/packages/server/src/adapters/warp_adapter.rs @@ -0,0 +1,28 @@ +use crate::{LiveViewError, LiveViewSocket}; +use futures_util::{SinkExt, StreamExt}; +use warp::ws::{Message, WebSocket}; + +/// Convert a warp websocket into a LiveViewSocket +/// +/// This is required to launch a LiveView app using the warp web framework +pub fn warp_socket(ws: WebSocket) -> impl LiveViewSocket { + ws.map(transform_rx) + .with(transform_tx) + .sink_map_err(|_| LiveViewError::SendingFailed) +} + +fn transform_rx(message: Result) -> Result { + // destructure the message into the buffer we got from warp + let msg = message + .map_err(|_| LiveViewError::SendingFailed)? + .into_bytes(); + + // transform it back into a string, saving us the allocation + let msg = String::from_utf8(msg).map_err(|_| LiveViewError::SendingFailed)?; + + Ok(msg) +} + +async fn transform_tx(message: String) -> Result { + Ok(Message::text(message)) +} diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs new file mode 100644 index 000000000..49b635fc2 --- /dev/null +++ b/packages/server/src/lib.rs @@ -0,0 +1,85 @@ +use dioxus::prelude::*; +use serde::{de::DeserializeOwned, Deserializer, Serialize, Serializer}; + +// We use deref specialization to make it possible to pass either a value that implements +pub trait SerializeToRemoteWrapper { + fn serialize_to_remote(&self, serializer: S) -> Result; +} + +impl SerializeToRemoteWrapper for &T { + fn serialize_to_remote( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> { + self.serialize(serializer) + } +} + +impl SerializeToRemoteWrapper for &mut &S { + fn serialize_to_remote( + &self, + serializer: S2, + ) -> Result<::Ok, ::Error> { + (**self).serialize_to_remote(serializer) + } +} + +pub trait SerializeToRemote { + fn serialize_to_remote(&self, serializer: S) -> Result; +} + +impl SerializeToRemote for UseState { + fn serialize_to_remote( + &self, + serializer: S2, + ) -> Result<::Ok, ::Error> { + self.current().serialize(serializer) + } +} + +// We use deref specialization to make it possible to pass either a value that implements +pub trait DeserializeOnRemoteWrapper { + type Output; + + fn deserialize_on_remote<'a, D: Deserializer<'a>>( + deserializer: D, + ) -> Result; +} + +impl DeserializeOnRemoteWrapper for &T { + type Output = T; + + fn deserialize_on_remote<'a, D: Deserializer<'a>>( + deserializer: D, + ) -> Result { + T::deserialize(deserializer) + } +} + +impl DeserializeOnRemoteWrapper for &mut &D { + type Output = D::Output; + + fn deserialize_on_remote<'a, D2: Deserializer<'a>>( + deserializer: D2, + ) -> Result { + D::deserialize_on_remote(deserializer) + } +} + +pub trait DeserializeOnRemote { + type Output; + + fn deserialize_on_remote<'a, D: Deserializer<'a>>( + deserializer: D, + ) -> Result; +} + +impl DeserializeOnRemote for UseState { + type Output = D; + + fn deserialize_on_remote<'a, D2: Deserializer<'a>>( + deserializer: D2, + ) -> Result { + D::deserialize(deserializer) + } +} From 939e75541e9bfbe67f0188df556e256b3032e343 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 29 Mar 2023 20:20:26 -0500 Subject: [PATCH 365/895] initial axum implementation --- packages/server/Cargo.toml | 15 +- packages/server/src/adapters/axum_adapter.rs | 116 +++++++++++-- packages/server/src/adapters/mod.rs | 2 + packages/server/src/lib.rs | 173 ++++++++++--------- 4 files changed, 211 insertions(+), 95 deletions(-) create mode 100644 packages/server/src/adapters/mod.rs diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 13704574b..4e3028aaa 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -18,4 +18,17 @@ axum = { version = "0.6.1", optional = true, features = ["ws"] } salvo = { version = "0.37.7", optional = true, features = ["ws"] } serde = "1.0.159" -dioxus = { path = "../dioxus", version = "^0.3.0" } \ No newline at end of file +dioxus = { path = "../dioxus", version = "^0.3.0" } + +log = "0.4.17" +once_cell = "1.17.1" +thiserror = "1.0.40" +hyper = "0.14.25" +tokio = { version = "1.27.0", features = ["full"] } + +[features] +default = ["axum", "ssr"] +warp = ["dep:warp"] +axum = ["dep:axum"] +salvo = ["dep:salvo"] +ssr = ["server_fn/ssr"] diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 646cde38e..3fb0a1d4e 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -1,23 +1,105 @@ -use crate::{LiveViewError, LiveViewSocket}; -use axum::extract::ws::{Message, WebSocket}; -use futures_util::{SinkExt, StreamExt}; +use std::{error::Error, sync::Arc}; -/// Convert a warp websocket into a LiveViewSocket -/// -/// This is required to launch a LiveView app using the warp web framework -pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket { - ws.map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) +use axum::{ + body::{self, Body, BoxBody, Full}, + http::{HeaderMap, Request, Response, StatusCode}, + response::IntoResponse, + routing::post, + Router, +}; +use server_fn::{Payload, ServerFunctionRegistry}; +use tokio::task::spawn_blocking; + +use crate::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}; + +trait DioxusRouterExt { + fn register_server_fns(self) -> Self; } -fn transform_rx(message: Result) -> Result { - message - .map_err(|_| LiveViewError::SendingFailed)? - .into_text() - .map_err(|_| LiveViewError::SendingFailed) +impl DioxusRouterExt for Router { + fn register_server_fns(self) -> Self { + let mut router = self; + for server_fn_path in DioxusServerFnRegistry::paths_registered() { + let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); + router = router.route( + server_fn_path, + post(move |headers: HeaderMap, body: Request| async move { + server_fn_handler(DioxusServerContext {}, func.clone(), headers, body).await + // todo!() + }), + ); + } + router + } } -async fn transform_tx(message: String) -> Result { - Ok(Message::Text(message)) +async fn server_fn_handler( + server_context: DioxusServerContext, + function: Arc, + headers: HeaderMap, + req: Request, +) -> impl IntoResponse { + let (_, body) = req.into_parts(); + let body = hyper::body::to_bytes(body).await; + let Ok(body)=body else { + return report_err(body.err().unwrap()); + }; + + // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime + let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); + spawn_blocking({ + move || { + tokio::runtime::Runtime::new() + .expect("couldn't spawn runtime") + .block_on(async { + let resp = match function(server_context, &body).await { + Ok(serialized) => { + // if this is Accept: application/json then send a serialized JSON response + let accept_header = + headers.get("Accept").and_then(|value| value.to_str().ok()); + let mut res = Response::builder(); + if accept_header == Some("application/json") + || accept_header + == Some( + "application/\ + x-www-form-urlencoded", + ) + || accept_header == Some("application/cbor") + { + res = res.status(StatusCode::OK); + } + + let resp = match serialized { + Payload::Binary(data) => res + .header("Content-Type", "application/cbor") + .body(body::boxed(Full::from(data))), + Payload::Url(data) => res + .header( + "Content-Type", + "application/\ + x-www-form-urlencoded", + ) + .body(body::boxed(data)), + Payload::Json(data) => res + .header("Content-Type", "application/json") + .body(body::boxed(data)), + }; + + resp.unwrap() + } + Err(e) => report_err(e), + }; + + resp_tx.send(resp).unwrap(); + }) + } + }); + resp_rx.await.unwrap() +} + +fn report_err(e: E) -> Response { + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(body::boxed(format!("Error: {}", e))) + .unwrap() } diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs new file mode 100644 index 000000000..ce2670dde --- /dev/null +++ b/packages/server/src/adapters/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "axum")] +mod axum_adapter; diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 49b635fc2..c0ec07e06 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -1,85 +1,104 @@ -use dioxus::prelude::*; -use serde::{de::DeserializeOwned, Deserializer, Serialize, Serializer}; +mod adapters; -// We use deref specialization to make it possible to pass either a value that implements -pub trait SerializeToRemoteWrapper { - fn serialize_to_remote(&self, serializer: S) -> Result; -} +// #[server(ReadPosts, "api")] +// async fn testing(rx: i32) -> Result { +// Ok(0) +// } -impl SerializeToRemoteWrapper for &T { - fn serialize_to_remote( - &self, - serializer: S, - ) -> Result<::Ok, ::Error> { - self.serialize(serializer) +pub struct DioxusServerContext {} + +#[cfg(any(feature = "ssr", doc))] +type ServerFnTraitObj = server_fn::ServerFnTraitObj; + +#[cfg(any(feature = "ssr", doc))] +static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< + std::sync::Arc< + std::sync::RwLock< + std::collections::HashMap<&'static str, std::sync::Arc>, + >, + >, +> = once_cell::sync::Lazy::new(Default::default); + +#[cfg(any(feature = "ssr", doc))] +/// The registry of all Dioxus server functions. +pub struct DioxusServerFnRegistry; + +#[cfg(any(feature = "ssr"))] +impl server_fn::ServerFunctionRegistry for DioxusServerFnRegistry { + type Error = ServerRegistrationFnError; + + fn register( + url: &'static str, + server_function: std::sync::Arc, + ) -> Result<(), Self::Error> { + // store it in the hashmap + let mut write = REGISTERED_SERVER_FUNCTIONS + .write() + .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?; + let prev = write.insert(url, server_function); + + // if there was already a server function with this key, + // return Err + match prev { + Some(_) => Err(ServerRegistrationFnError::AlreadyRegistered(format!( + "There was already a server function registered at {:?}. \ + This can happen if you use the same server function name \ + in two different modules + on `stable` or in `release` mode.", + url + ))), + None => Ok(()), + } + } + + /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL. + fn get(url: &str) -> Option> { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .and_then(|fns| fns.get(url).cloned()) + } + + /// Returns a list of all registered server functions. + fn paths_registered() -> Vec<&'static str> { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .map(|fns| fns.keys().cloned().collect()) + .unwrap_or_default() } } -impl SerializeToRemoteWrapper for &mut &S { - fn serialize_to_remote( - &self, - serializer: S2, - ) -> Result<::Ok, ::Error> { - (**self).serialize_to_remote(serializer) +#[cfg(any(feature = "ssr", doc))] +/// Errors that can occur when registering a server function. +#[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)] +pub enum ServerRegistrationFnError { + /// The server function is already registered. + #[error("The server function {0} is already registered")] + AlreadyRegistered(String), + /// The server function registry is poisoned. + #[error("The server function registry is poisoned: {0}")] + Poisoned(String), +} + +/// Defines a "server function." A server function can be called from the server or the client, +/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. +/// +/// (This follows the same convention as the Dioxus framework's distinction between `ssr` for server-side rendering, +/// and `csr` and `hydrate` for client-side rendering and hydration, respectively.) +/// +/// Server functions are created using the `server` macro. +/// +/// The function should be registered by calling `ServerFn::register()`. The set of server functions +/// can be queried on the server for routing purposes by calling [server_fn_by_path]. +/// +/// Technically, the trait is implemented on a type that describes the server function's arguments. +pub trait ServerFn: server_fn::ServerFn { + /// Registers the server function, allowing the server to query it by URL. + #[cfg(any(feature = "ssr", doc))] + fn register() -> Result<(), server_fn::ServerFnError> { + Self::register_in::() } } -pub trait SerializeToRemote { - fn serialize_to_remote(&self, serializer: S) -> Result; -} - -impl SerializeToRemote for UseState { - fn serialize_to_remote( - &self, - serializer: S2, - ) -> Result<::Ok, ::Error> { - self.current().serialize(serializer) - } -} - -// We use deref specialization to make it possible to pass either a value that implements -pub trait DeserializeOnRemoteWrapper { - type Output; - - fn deserialize_on_remote<'a, D: Deserializer<'a>>( - deserializer: D, - ) -> Result; -} - -impl DeserializeOnRemoteWrapper for &T { - type Output = T; - - fn deserialize_on_remote<'a, D: Deserializer<'a>>( - deserializer: D, - ) -> Result { - T::deserialize(deserializer) - } -} - -impl DeserializeOnRemoteWrapper for &mut &D { - type Output = D::Output; - - fn deserialize_on_remote<'a, D2: Deserializer<'a>>( - deserializer: D2, - ) -> Result { - D::deserialize_on_remote(deserializer) - } -} - -pub trait DeserializeOnRemote { - type Output; - - fn deserialize_on_remote<'a, D: Deserializer<'a>>( - deserializer: D, - ) -> Result; -} - -impl DeserializeOnRemote for UseState { - type Output = D; - - fn deserialize_on_remote<'a, D2: Deserializer<'a>>( - deserializer: D2, - ) -> Result { - D::deserialize(deserializer) - } -} +impl ServerFn for T where T: server_fn::ServerFn {} From fdc8ebd1b196fddf5abd2cbc50cbd98c9fc0f912 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 10:34:13 -0500 Subject: [PATCH 366/895] create fullstack hello world example --- packages/server/.gitignore | 1 + packages/server/Cargo.toml | 23 ++- .../server/examples/hello-world/.gitignore | 2 + .../server/examples/hello-world/Cargo.toml | 20 +++ .../server/examples/hello-world/src/main.rs | 70 +++++++++ packages/server/server_macro/Cargo.toml | 6 + packages/server/server_macro/src/lib.rs | 10 +- packages/server/src/adapters/axum_adapter.rs | 49 +++++- packages/server/src/adapters/mod.rs | 2 +- packages/server/src/lib.rs | 148 ++++++------------ packages/server/src/server_fn.rs | 98 ++++++++++++ 11 files changed, 312 insertions(+), 117 deletions(-) create mode 100644 packages/server/.gitignore create mode 100644 packages/server/examples/hello-world/.gitignore create mode 100644 packages/server/examples/hello-world/Cargo.toml create mode 100644 packages/server/examples/hello-world/src/main.rs create mode 100644 packages/server/src/server_fn.rs diff --git a/packages/server/.gitignore b/packages/server/.gitignore new file mode 100644 index 000000000..1de565933 --- /dev/null +++ b/packages/server/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 4e3028aaa..af7e03859 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "server" +name = "dioxus-server" version = "0.1.0" edition = "2021" @@ -7,28 +7,37 @@ edition = "2021" [dependencies] server_fn = { version = "0.2.4", features = ["stable"] } +server_macro = { path = "server_macro" } # warp warp = { version = "0.3.3", optional = true } # axum axum = { version = "0.6.1", optional = true, features = ["ws"] } +tower-http = { version = "0.4.0", optional = true, features = ["fs"] } +hyper = { version = "0.14.25", optional = true } # salvo salvo = { version = "0.37.7", optional = true, features = ["ws"] } serde = "1.0.159" -dioxus = { path = "../dioxus", version = "^0.3.0" } +dioxus-core = { path = "../core", version = "^0.3.0" } +dioxus-ssr = { path = "../ssr", version = "^0.3.0", optional = true } log = "0.4.17" once_cell = "1.17.1" thiserror = "1.0.40" -hyper = "0.14.25" -tokio = { version = "1.27.0", features = ["full"] } +tokio = { version = "1.27.0", features = ["full"], optional = true } [features] -default = ["axum", "ssr"] +default = [] warp = ["dep:warp"] -axum = ["dep:axum"] +axum = ["dep:axum", "tower-http", "hyper"] salvo = ["dep:salvo"] -ssr = ["server_fn/ssr"] +ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] + +[workspace] +members = [ + "server_macro", + "examples/hello-world", +] \ No newline at end of file diff --git a/packages/server/examples/hello-world/.gitignore b/packages/server/examples/hello-world/.gitignore new file mode 100644 index 000000000..6047329c6 --- /dev/null +++ b/packages/server/examples/hello-world/.gitignore @@ -0,0 +1,2 @@ +dist +target \ No newline at end of file diff --git a/packages/server/examples/hello-world/Cargo.toml b/packages/server/examples/hello-world/Cargo.toml new file mode 100644 index 000000000..846c03ea4 --- /dev/null +++ b/packages/server/examples/hello-world/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "hello-world" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } +dioxus = { path = "../../../dioxus" } +dioxus-server = { path = "../../" } +axum = { version = "0.6.12", optional = true } +tokio = { version = "1.27.0", features = ["full"], optional = true } +serde = "1.0.159" +tracing-subscriber = "0.3.16" +tracing = "0.1.37" + +[features] +ssr = ["axum", "tokio", "dioxus-server/ssr", "dioxus-server/axum"] +web = ["dioxus-web"] diff --git a/packages/server/examples/hello-world/src/main.rs b/packages/server/examples/hello-world/src/main.rs new file mode 100644 index 000000000..9b9084963 --- /dev/null +++ b/packages/server/examples/hello-world/src/main.rs @@ -0,0 +1,70 @@ +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + PostServerData::register().unwrap(); + GetServerData::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .serve_dioxus_application( + "Hello, world!", + "hello-world", + None, + None, + "", + app, + ) + .into_make_service(), + ) + .await + .unwrap(); + }); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + let text = use_state(cx, || "...".to_string()); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![text]; + async move { + if let Ok(data) = get_server_data().await { + println!("Client received: {}", data); + text.set(data.clone()); + post_server_data(data).await.unwrap(); + } + } + }, + "Run a server function" + } + "Server said: {text}" + }) +} + +#[server(PostServerData)] +async fn post_server_data(data: String) -> Result<(), ServerFnError> { + println!("Server received: {}", data); + + Ok(()) +} + +#[server(GetServerData)] +async fn get_server_data() -> Result { + Ok("Hello from the server!".to_string()) +} diff --git a/packages/server/server_macro/Cargo.toml b/packages/server/server_macro/Cargo.toml index 6e8c69b46..cb285f517 100644 --- a/packages/server/server_macro/Cargo.toml +++ b/packages/server/server_macro/Cargo.toml @@ -6,3 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +quote = "1.0.26" +server_fn_macro = { version = "0.2.4", features = ["stable"] } +syn = { version = "1", features = ["full"] } + +[lib] +proc-macro = true diff --git a/packages/server/server_macro/src/lib.rs b/packages/server/server_macro/src/lib.rs index 439a9e7b2..f2a2e1665 100644 --- a/packages/server/server_macro/src/lib.rs +++ b/packages/server/server_macro/src/lib.rs @@ -1,3 +1,7 @@ +use proc_macro::TokenStream; +use quote::ToTokens; +use server_fn_macro::*; + /// Declares that a function is a [server function](leptos_server). This means that /// its body will only run on the server, i.e., when the `ssr` feature is enabled. /// @@ -52,14 +56,14 @@ #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { let context = ServerContext { - ty: syn::parse_quote!(Scope), - path: syn::parse_quote!(::leptos::Scope), + ty: syn::parse_quote!(DioxusServerContext), + path: syn::parse_quote!(::dioxus_server::prelude::DioxusServerContext), }; match server_macro_impl( args.into(), s.into(), Some(context), - Some(syn::parse_quote!(::leptos::server_fn)), + Some(syn::parse_quote!(::dioxus_server::prelude::server_fn)), ) { Err(e) => e.to_compile_error().into(), Ok(s) => s.to_token_stream().into(), diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 3fb0a1d4e..70513bdb3 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -4,33 +4,68 @@ use axum::{ body::{self, Body, BoxBody, Full}, http::{HeaderMap, Request, Response, StatusCode}, response::IntoResponse, - routing::post, + routing::{get, post}, Router, }; +use dioxus_core::Component; use server_fn::{Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; -use crate::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}; +use crate::{ + dioxus_ssr_html, + server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, +}; -trait DioxusRouterExt { - fn register_server_fns(self) -> Self; +pub trait DioxusRouterExt { + fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn serve_dioxus_application( + self, + title: &'static str, + application_name: &'static str, + base_path: Option<&'static str>, + head: Option<&'static str>, + server_fn_route: &'static str, + app: Component, + ) -> Self; } impl DioxusRouterExt for Router { - fn register_server_fns(self) -> Self { + fn register_server_fns(self, server_fn_route: &'static str) -> Self { let mut router = self; for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); + let full_route = format!("{server_fn_route}/{server_fn_path}"); router = router.route( - server_fn_path, + &full_route, post(move |headers: HeaderMap, body: Request| async move { server_fn_handler(DioxusServerContext {}, func.clone(), headers, body).await - // todo!() }), ); } router } + + fn serve_dioxus_application( + self, + title: &'static str, + application_name: &'static str, + base_path: Option<&'static str>, + head: Option<&'static str>, + server_fn_route: &'static str, + app: Component, + ) -> Self { + use tower_http::services::ServeDir; + + // Serve the dist folder and the index.html file + let serve_dir = ServeDir::new("dist"); + + self.register_server_fns(server_fn_route) + .nest_service("/", serve_dir) + .fallback_service(get(move || { + let rendered = dioxus_ssr_html(title, application_name, base_path, head, app); + async move { Full::from(rendered) } + })) + } } async fn server_fn_handler( diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs index ce2670dde..c30365989 100644 --- a/packages/server/src/adapters/mod.rs +++ b/packages/server/src/adapters/mod.rs @@ -1,2 +1,2 @@ #[cfg(feature = "axum")] -mod axum_adapter; +pub mod axum_adapter; diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index c0ec07e06..c78f3471b 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -1,104 +1,54 @@ +#[allow(unused)] +use dioxus_core::prelude::*; + mod adapters; +mod server_fn; -// #[server(ReadPosts, "api")] -// async fn testing(rx: i32) -> Result { -// Ok(0) -// } - -pub struct DioxusServerContext {} - -#[cfg(any(feature = "ssr", doc))] -type ServerFnTraitObj = server_fn::ServerFnTraitObj; - -#[cfg(any(feature = "ssr", doc))] -static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< - std::sync::Arc< - std::sync::RwLock< - std::collections::HashMap<&'static str, std::sync::Arc>, - >, - >, -> = once_cell::sync::Lazy::new(Default::default); - -#[cfg(any(feature = "ssr", doc))] -/// The registry of all Dioxus server functions. -pub struct DioxusServerFnRegistry; - -#[cfg(any(feature = "ssr"))] -impl server_fn::ServerFunctionRegistry for DioxusServerFnRegistry { - type Error = ServerRegistrationFnError; - - fn register( - url: &'static str, - server_function: std::sync::Arc, - ) -> Result<(), Self::Error> { - // store it in the hashmap - let mut write = REGISTERED_SERVER_FUNCTIONS - .write() - .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?; - let prev = write.insert(url, server_function); - - // if there was already a server function with this key, - // return Err - match prev { - Some(_) => Err(ServerRegistrationFnError::AlreadyRegistered(format!( - "There was already a server function registered at {:?}. \ - This can happen if you use the same server function name \ - in two different modules - on `stable` or in `release` mode.", - url - ))), - None => Ok(()), - } - } - - /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL. - fn get(url: &str) -> Option> { - REGISTERED_SERVER_FUNCTIONS - .read() - .ok() - .and_then(|fns| fns.get(url).cloned()) - } - - /// Returns a list of all registered server functions. - fn paths_registered() -> Vec<&'static str> { - REGISTERED_SERVER_FUNCTIONS - .read() - .ok() - .map(|fns| fns.keys().cloned().collect()) - .unwrap_or_default() - } +pub mod prelude { + #[cfg(feature = "axum")] + pub use crate::adapters::axum_adapter::*; + pub use crate::server_fn::{DioxusServerContext, ServerFn}; + pub use server_fn::{self, ServerFn as _, ServerFnError}; + pub use server_macro::*; } -#[cfg(any(feature = "ssr", doc))] -/// Errors that can occur when registering a server function. -#[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)] -pub enum ServerRegistrationFnError { - /// The server function is already registered. - #[error("The server function {0} is already registered")] - AlreadyRegistered(String), - /// The server function registry is poisoned. - #[error("The server function registry is poisoned: {0}")] - Poisoned(String), +#[cfg(feature = "ssr")] +fn dioxus_ssr_html( + title: &str, + application_name: &str, + base_path: Option<&str>, + head: Option<&str>, + app: Component, +) -> String { + let mut vdom = VirtualDom::new(app); + let _ = vdom.rebuild(); + let renderered = dioxus_ssr::pre_render(&vdom); + let base_path = base_path.unwrap_or("."); + let head = head.unwrap_or_default(); + format!( + r#" + + + + {title} + + + + {head} + + +
+ {renderered} +
+ + +"# + ) } - -/// Defines a "server function." A server function can be called from the server or the client, -/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. -/// -/// (This follows the same convention as the Dioxus framework's distinction between `ssr` for server-side rendering, -/// and `csr` and `hydrate` for client-side rendering and hydration, respectively.) -/// -/// Server functions are created using the `server` macro. -/// -/// The function should be registered by calling `ServerFn::register()`. The set of server functions -/// can be queried on the server for routing purposes by calling [server_fn_by_path]. -/// -/// Technically, the trait is implemented on a type that describes the server function's arguments. -pub trait ServerFn: server_fn::ServerFn { - /// Registers the server function, allowing the server to query it by URL. - #[cfg(any(feature = "ssr", doc))] - fn register() -> Result<(), server_fn::ServerFnError> { - Self::register_in::() - } -} - -impl ServerFn for T where T: server_fn::ServerFn {} diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs new file mode 100644 index 000000000..28c7cd9b6 --- /dev/null +++ b/packages/server/src/server_fn.rs @@ -0,0 +1,98 @@ +pub struct DioxusServerContext {} + +#[cfg(any(feature = "ssr", doc))] +pub type ServerFnTraitObj = server_fn::ServerFnTraitObj; + +#[cfg(any(feature = "ssr", doc))] +#[allow(clippy::type_complexity)] +static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< + std::sync::Arc< + std::sync::RwLock< + std::collections::HashMap<&'static str, std::sync::Arc>, + >, + >, +> = once_cell::sync::Lazy::new(Default::default); + +#[cfg(any(feature = "ssr", doc))] +/// The registry of all Dioxus server functions. +pub struct DioxusServerFnRegistry; + +#[cfg(any(feature = "ssr"))] +impl server_fn::ServerFunctionRegistry for DioxusServerFnRegistry { + type Error = ServerRegistrationFnError; + + fn register( + url: &'static str, + server_function: std::sync::Arc, + ) -> Result<(), Self::Error> { + // store it in the hashmap + let mut write = REGISTERED_SERVER_FUNCTIONS + .write() + .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?; + let prev = write.insert(url, server_function); + + // if there was already a server function with this key, + // return Err + match prev { + Some(_) => Err(ServerRegistrationFnError::AlreadyRegistered(format!( + "There was already a server function registered at {:?}. \ + This can happen if you use the same server function name \ + in two different modules + on `stable` or in `release` mode.", + url + ))), + None => Ok(()), + } + } + + /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL. + fn get(url: &str) -> Option> { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .and_then(|fns| fns.get(url).cloned()) + } + + /// Returns a list of all registered server functions. + fn paths_registered() -> Vec<&'static str> { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .map(|fns| fns.keys().cloned().collect()) + .unwrap_or_default() + } +} + +#[cfg(any(feature = "ssr", doc))] +/// Errors that can occur when registering a server function. +#[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)] +pub enum ServerRegistrationFnError { + /// The server function is already registered. + #[error("The server function {0} is already registered")] + AlreadyRegistered(String), + /// The server function registry is poisoned. + #[error("The server function registry is poisoned: {0}")] + Poisoned(String), +} + +/// Defines a "server function." A server function can be called from the server or the client, +/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. +/// +/// (This follows the same convention as the Dioxus framework's distinction between `ssr` for server-side rendering, +/// and `csr` and `hydrate` for client-side rendering and hydration, respectively.) +/// +/// Server functions are created using the `server` macro. +/// +/// The function should be registered by calling `ServerFn::register()`. The set of server functions +/// can be queried on the server for routing purposes by calling [server_fn_by_path]. +/// +/// Technically, the trait is implemented on a type that describes the server function's arguments. +pub trait ServerFn: server_fn::ServerFn { + /// Registers the server function, allowing the server to query it by URL. + #[cfg(any(feature = "ssr", doc))] + fn register() -> Result<(), server_fn::ServerFnError> { + Self::register_in::() + } +} + +impl ServerFn for T where T: server_fn::ServerFn {} From 1d395d572f2f642174378cf2a1e3e99695702726 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 10:38:32 -0500 Subject: [PATCH 367/895] fix workspace build --- Cargo.toml | 2 ++ packages/server/Cargo.toml | 8 +------- packages/server/{server_macro => server-macro}/Cargo.toml | 0 packages/server/{server_macro => server-macro}/src/lib.rs | 0 4 files changed, 3 insertions(+), 7 deletions(-) rename packages/server/{server_macro => server-macro}/Cargo.toml (100%) rename packages/server/{server_macro => server-macro}/src/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 3b36bb5e3..8389566ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ members = [ "packages/signals", "packages/hot-reload", "packages/server", + "packages/server/server-macro", + "packages/server/examples/hello-world", "docs/guide", ] diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index af7e03859..57ad88da1 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] server_fn = { version = "0.2.4", features = ["stable"] } -server_macro = { path = "server_macro" } +server_macro = { path = "server-macro" } # warp warp = { version = "0.3.3", optional = true } @@ -35,9 +35,3 @@ warp = ["dep:warp"] axum = ["dep:axum", "tower-http", "hyper"] salvo = ["dep:salvo"] ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] - -[workspace] -members = [ - "server_macro", - "examples/hello-world", -] \ No newline at end of file diff --git a/packages/server/server_macro/Cargo.toml b/packages/server/server-macro/Cargo.toml similarity index 100% rename from packages/server/server_macro/Cargo.toml rename to packages/server/server-macro/Cargo.toml diff --git a/packages/server/server_macro/src/lib.rs b/packages/server/server-macro/src/lib.rs similarity index 100% rename from packages/server/server_macro/src/lib.rs rename to packages/server/server-macro/src/lib.rs From 2c787f85f47deeda4bbfa81802592989e742a5f4 Mon Sep 17 00:00:00 2001 From: Ben Schulz Date: Thu, 30 Mar 2023 18:01:18 +0200 Subject: [PATCH 368/895] =?UTF-8?q?Add=20proxy=20routes=20in=20startup=5Fd?= =?UTF-8?q?efault(=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index e78a8fb84..42622466b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -447,7 +447,9 @@ pub async fn startup_default(ip: String, port: u16, config: CrateConfig) -> Resu .service(ServeDir::new(config.crate_dir.join(&dist_path))); let mut router = Router::new().route("/_dioxus/ws", get(ws_handler)); - + for proxy_config in config.dioxus_config.web.proxy.unwrap_or_default() { + router = proxy::add_proxy(router, &proxy_config)?; + } router = router .fallback( get_service(file_service).handle_error(|error: std::io::Error| async move { From 1be48c4aa8cdb45f5a35014e59c4f62b8d21a906 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 11:03:07 -0500 Subject: [PATCH 369/895] create a serveconfig builder --- .../server/examples/hello-world/src/main.rs | 7 +-- packages/server/src/adapters/axum_adapter.rs | 26 ++-------- packages/server/src/lib.rs | 33 ++++++++----- packages/server/src/serve.rs | 47 +++++++++++++++++++ 4 files changed, 74 insertions(+), 39 deletions(-) create mode 100644 packages/server/src/serve.rs diff --git a/packages/server/examples/hello-world/src/main.rs b/packages/server/examples/hello-world/src/main.rs index 9b9084963..9cafe93b5 100644 --- a/packages/server/examples/hello-world/src/main.rs +++ b/packages/server/examples/hello-world/src/main.rs @@ -17,12 +17,7 @@ fn main() { .serve( axum::Router::new() .serve_dioxus_application( - "Hello, world!", - "hello-world", - None, - None, - "", - app, + ServeConfig::new(app).head(r#"Hello World!"#), ) .into_make_service(), ) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 70513bdb3..649629f61 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -7,26 +7,18 @@ use axum::{ routing::{get, post}, Router, }; -use dioxus_core::Component; use server_fn::{Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; use crate::{ dioxus_ssr_html, + serve::ServeConfig, server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, }; pub trait DioxusRouterExt { fn register_server_fns(self, server_fn_route: &'static str) -> Self; - fn serve_dioxus_application( - self, - title: &'static str, - application_name: &'static str, - base_path: Option<&'static str>, - head: Option<&'static str>, - server_fn_route: &'static str, - app: Component, - ) -> Self; + fn serve_dioxus_application(self, cfg: ServeConfig) -> Self; } impl DioxusRouterExt for Router { @@ -45,24 +37,16 @@ impl DioxusRouterExt for Router { router } - fn serve_dioxus_application( - self, - title: &'static str, - application_name: &'static str, - base_path: Option<&'static str>, - head: Option<&'static str>, - server_fn_route: &'static str, - app: Component, - ) -> Self { + fn serve_dioxus_application(self, cfg: ServeConfig) -> Self { use tower_http::services::ServeDir; // Serve the dist folder and the index.html file let serve_dir = ServeDir::new("dist"); - self.register_server_fns(server_fn_route) + self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) .nest_service("/", serve_dir) .fallback_service(get(move || { - let rendered = dioxus_ssr_html(title, application_name, base_path, head, app); + let rendered = dioxus_ssr_html(cfg); async move { Full::from(rendered) } })) } diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index c78f3471b..e14a445b5 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -2,38 +2,47 @@ use dioxus_core::prelude::*; mod adapters; +mod serve; mod server_fn; pub mod prelude { #[cfg(feature = "axum")] pub use crate::adapters::axum_adapter::*; + pub use crate::serve::ServeConfig; pub use crate::server_fn::{DioxusServerContext, ServerFn}; pub use server_fn::{self, ServerFn as _, ServerFnError}; pub use server_macro::*; } #[cfg(feature = "ssr")] -fn dioxus_ssr_html( - title: &str, - application_name: &str, - base_path: Option<&str>, - head: Option<&str>, - app: Component, -) -> String { +fn dioxus_ssr_html(cfg: serve::ServeConfig) -> String { + use prelude::ServeConfig; + + let ServeConfig { + app, + application_name, + base_path, + head, + .. + } = cfg; + + let application_name = application_name.unwrap_or("dioxus"); + let mut vdom = VirtualDom::new(app); let _ = vdom.rebuild(); let renderered = dioxus_ssr::pre_render(&vdom); let base_path = base_path.unwrap_or("."); - let head = head.unwrap_or_default(); + let head = head.unwrap_or( + r#"Dioxus Application + + + "#, + ); format!( r#" - {title} - - - {head} diff --git a/packages/server/src/serve.rs b/packages/server/src/serve.rs new file mode 100644 index 000000000..7dc1eaaac --- /dev/null +++ b/packages/server/src/serve.rs @@ -0,0 +1,47 @@ +use dioxus_core::Component; + +#[derive(Clone)] +pub struct ServeConfig { + pub(crate) app: Component, + pub(crate) application_name: Option<&'static str>, + pub(crate) server_fn_route: Option<&'static str>, + pub(crate) base_path: Option<&'static str>, + pub(crate) head: Option<&'static str>, +} + +impl ServeConfig { + /// Create a new ServeConfig + pub fn new(app: Component) -> Self { + Self { + app, + application_name: None, + server_fn_route: None, + base_path: None, + head: None, + } + } + + /// Set the application name matching the name in the Dioxus.toml file used to build the application + pub fn application_name(mut self, application_name: &'static str) -> Self { + self.application_name = Some(application_name); + self + } + + /// Set the base route all server functions will be served under + pub fn server_fn_route(mut self, server_fn_route: &'static str) -> Self { + self.server_fn_route = Some(server_fn_route); + self + } + + /// Set the path the WASM application will be served under + pub fn base_path(mut self, base_path: &'static str) -> Self { + self.base_path = Some(base_path); + self + } + + /// Set the head content to be included in the HTML document served + pub fn head(mut self, head: &'static str) -> Self { + self.head = Some(head); + self + } +} From 39a5fbf26861c10be16abeb403378c7136137f24 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 15:58:03 -0500 Subject: [PATCH 370/895] add build instuctions --- packages/server/examples/hello-world/src/main.rs | 7 +++++++ packages/server/src/adapters/axum_adapter.rs | 4 ++-- packages/server/src/lib.rs | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/server/examples/hello-world/src/main.rs b/packages/server/examples/hello-world/src/main.rs index 9cafe93b5..2fd6b1bde 100644 --- a/packages/server/examples/hello-world/src/main.rs +++ b/packages/server/examples/hello-world/src/main.rs @@ -1,3 +1,10 @@ +//! Run with: +//! +//! ```sh +//! dioxus build --features web +//! cargo run --features ssr +//! ``` + #![allow(non_snake_case)] use dioxus::prelude::*; use dioxus_server::prelude::*; diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 649629f61..b7cc85e1c 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -44,11 +44,11 @@ impl DioxusRouterExt for Router { let serve_dir = ServeDir::new("dist"); self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) - .nest_service("/", serve_dir) - .fallback_service(get(move || { + .route("/", get(move || { let rendered = dioxus_ssr_html(cfg); async move { Full::from(rendered) } })) + .fallback_service( serve_dir) } } diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index e14a445b5..98261d1d4 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -2,12 +2,14 @@ use dioxus_core::prelude::*; mod adapters; +#[cfg(feature = "ssr")] mod serve; mod server_fn; pub mod prelude { #[cfg(feature = "axum")] pub use crate::adapters::axum_adapter::*; + #[cfg(feature = "ssr")] pub use crate::serve::ServeConfig; pub use crate::server_fn::{DioxusServerContext, ServerFn}; pub use server_fn::{self, ServerFn as _, ServerFnError}; From f618da7311df3766fa96faf03485853c6d4cd716 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 19:42:46 -0500 Subject: [PATCH 371/895] allow passing props to the rendered component --- Cargo.toml | 3 ++- packages/server/Cargo.toml | 6 +++--- packages/server/src/adapters/mod.rs | 2 ++ packages/server/src/lib.rs | 7 +++++-- packages/server/src/serve.rs | 10 ++++++---- packages/server/src/server_fn.rs | 1 + 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8389566ee..bf2b4b8c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,8 @@ members = [ "packages/hot-reload", "packages/server", "packages/server/server-macro", - "packages/server/examples/hello-world", + "packages/server/examples/axum-hello-world", + "packages/server/examples/salvo-hello-world", "docs/guide", ] diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 57ad88da1..fc5f33c7f 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -13,12 +13,12 @@ server_macro = { path = "server-macro" } warp = { version = "0.3.3", optional = true } # axum -axum = { version = "0.6.1", optional = true, features = ["ws"] } +axum = { version = "0.6.1", optional = true } tower-http = { version = "0.4.0", optional = true, features = ["fs"] } hyper = { version = "0.14.25", optional = true } # salvo -salvo = { version = "0.37.7", optional = true, features = ["ws"] } +salvo = { version = "0.37.7", optional = true, features = ["serve-static"] } serde = "1.0.159" dioxus-core = { path = "../core", version = "^0.3.0" } @@ -33,5 +33,5 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } default = [] warp = ["dep:warp"] axum = ["dep:axum", "tower-http", "hyper"] -salvo = ["dep:salvo"] +salvo = ["dep:salvo", "hyper"] ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs index c30365989..41bb4a403 100644 --- a/packages/server/src/adapters/mod.rs +++ b/packages/server/src/adapters/mod.rs @@ -1,2 +1,4 @@ #[cfg(feature = "axum")] pub mod axum_adapter; +#[cfg(feature = "salvo")] +pub mod salvo_adapter; diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 98261d1d4..e7559363a 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -9,6 +9,8 @@ mod server_fn; pub mod prelude { #[cfg(feature = "axum")] pub use crate::adapters::axum_adapter::*; + #[cfg(feature = "salvo")] + pub use crate::adapters::salvo_adapter::*; #[cfg(feature = "ssr")] pub use crate::serve::ServeConfig; pub use crate::server_fn::{DioxusServerContext, ServerFn}; @@ -17,7 +19,7 @@ pub mod prelude { } #[cfg(feature = "ssr")] -fn dioxus_ssr_html(cfg: serve::ServeConfig) -> String { +fn dioxus_ssr_html(cfg: &serve::ServeConfig

) -> String { use prelude::ServeConfig; let ServeConfig { @@ -25,12 +27,13 @@ fn dioxus_ssr_html(cfg: serve::ServeConfig) -> String { application_name, base_path, head, + props, .. } = cfg; let application_name = application_name.unwrap_or("dioxus"); - let mut vdom = VirtualDom::new(app); + let mut vdom = VirtualDom::new_with_props(*app, props.clone()); let _ = vdom.rebuild(); let renderered = dioxus_ssr::pre_render(&vdom); let base_path = base_path.unwrap_or("."); diff --git a/packages/server/src/serve.rs b/packages/server/src/serve.rs index 7dc1eaaac..9cca17a6b 100644 --- a/packages/server/src/serve.rs +++ b/packages/server/src/serve.rs @@ -1,19 +1,21 @@ use dioxus_core::Component; #[derive(Clone)] -pub struct ServeConfig { - pub(crate) app: Component, +pub struct ServeConfig { + pub(crate) app: Component

, + pub(crate) props: P, pub(crate) application_name: Option<&'static str>, pub(crate) server_fn_route: Option<&'static str>, pub(crate) base_path: Option<&'static str>, pub(crate) head: Option<&'static str>, } -impl ServeConfig { +impl ServeConfig

{ /// Create a new ServeConfig - pub fn new(app: Component) -> Self { + pub fn new(app: Component

, props: P) -> Self { Self { app, + props, application_name: None, server_fn_route: None, base_path: None, diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs index 28c7cd9b6..2f000adda 100644 --- a/packages/server/src/server_fn.rs +++ b/packages/server/src/server_fn.rs @@ -1,3 +1,4 @@ +#[derive(Clone)] pub struct DioxusServerContext {} #[cfg(any(feature = "ssr", doc))] From 83d513ef362f6cc17bd18d4c53bd9db7ebea3450 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 19:42:53 -0500 Subject: [PATCH 372/895] add salvo intigration --- .../.gitignore | 0 .../Cargo.toml | 2 +- .../src/main.rs | 4 +- .../examples/salvo-hello-world/.gitignore | 2 + .../examples/salvo-hello-world/Cargo.toml | 20 +++ .../examples/salvo-hello-world/src/main.rs | 68 ++++++++ packages/server/src/adapters/salvo_adapter.rs | 161 ++++++++++++++++-- 7 files changed, 238 insertions(+), 19 deletions(-) rename packages/server/examples/{hello-world => axum-hello-world}/.gitignore (100%) rename packages/server/examples/{hello-world => axum-hello-world}/Cargo.toml (95%) rename packages/server/examples/{hello-world => axum-hello-world}/src/main.rs (95%) create mode 100644 packages/server/examples/salvo-hello-world/.gitignore create mode 100644 packages/server/examples/salvo-hello-world/Cargo.toml create mode 100644 packages/server/examples/salvo-hello-world/src/main.rs diff --git a/packages/server/examples/hello-world/.gitignore b/packages/server/examples/axum-hello-world/.gitignore similarity index 100% rename from packages/server/examples/hello-world/.gitignore rename to packages/server/examples/axum-hello-world/.gitignore diff --git a/packages/server/examples/hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml similarity index 95% rename from packages/server/examples/hello-world/Cargo.toml rename to packages/server/examples/axum-hello-world/Cargo.toml index 846c03ea4..54aaf17d3 100644 --- a/packages/server/examples/hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hello-world" +name = "axum-hello-world" version = "0.1.0" edition = "2021" diff --git a/packages/server/examples/hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs similarity index 95% rename from packages/server/examples/hello-world/src/main.rs rename to packages/server/examples/axum-hello-world/src/main.rs index 2fd6b1bde..4d4ab5e78 100644 --- a/packages/server/examples/hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -1,5 +1,5 @@ //! Run with: -//! +//! //! ```sh //! dioxus build --features web //! cargo run --features ssr @@ -24,7 +24,7 @@ fn main() { .serve( axum::Router::new() .serve_dioxus_application( - ServeConfig::new(app).head(r#"Hello World!"#), + ServeConfig::new(app, ()).head(r#"Hello World!"#), ) .into_make_service(), ) diff --git a/packages/server/examples/salvo-hello-world/.gitignore b/packages/server/examples/salvo-hello-world/.gitignore new file mode 100644 index 000000000..6047329c6 --- /dev/null +++ b/packages/server/examples/salvo-hello-world/.gitignore @@ -0,0 +1,2 @@ +dist +target \ No newline at end of file diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml new file mode 100644 index 000000000..1ebe56dfc --- /dev/null +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "salvo-hello-world" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } +dioxus = { path = "../../../dioxus" } +dioxus-server = { path = "../../" } +tokio = { version = "1.27.0", features = ["full"], optional = true } +serde = "1.0.159" +tracing-subscriber = "0.3.16" +tracing = "0.1.37" +salvo = { version = "0.37.9", optional = true } + +[features] +ssr = ["salvo", "tokio", "dioxus-server/ssr", "dioxus-server/salvo"] +web = ["dioxus-web"] diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs new file mode 100644 index 000000000..cd8b80c51 --- /dev/null +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -0,0 +1,68 @@ +//! Run with: +//! +//! ```sh +//! dioxus build --features web +//! cargo run --features ssr +//! ``` + +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + use salvo::prelude::*; + PostServerData::register().unwrap(); + GetServerData::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let router = Router::new().serve_dioxus_application( + ServeConfig::new(app, ()).head(r#"Hello World!"#), + ); + Server::new(TcpListener::bind("127.0.0.1:8080")) + .serve(router) + .await; + }); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + let text = use_state(cx, || "...".to_string()); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![text]; + async move { + if let Ok(data) = get_server_data().await { + println!("Client received: {}", data); + text.set(data.clone()); + post_server_data(data).await.unwrap(); + } + } + }, + "Run a server function" + } + "Server said: {text}" + }) +} + +#[server(PostServerData)] +async fn post_server_data(data: String) -> Result<(), ServerFnError> { + println!("Server received: {}", data); + + Ok(()) +} + +#[server(GetServerData)] +async fn get_server_data() -> Result { + Ok("Hello from the server!".to_string()) +} diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 2c8912a57..20edc9364 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -1,25 +1,154 @@ -use futures_util::{SinkExt, StreamExt}; -use salvo::ws::{Message, WebSocket}; +use std::{error::Error, sync::Arc}; -use crate::{LiveViewError, LiveViewSocket}; +use hyper::{http::HeaderValue, StatusCode}; +use salvo::{ + async_trait, handler, serve_static::StaticDir, Depot, FlowCtrl, Handler, Request, Response, + Router, +}; +use server_fn::{Payload, ServerFunctionRegistry}; +use tokio::task::spawn_blocking; -/// Convert a salvo websocket into a LiveViewSocket -/// -/// This is required to launch a LiveView app using the warp web framework -pub fn salvo_socket(ws: WebSocket) -> impl LiveViewSocket { - ws.map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) +use crate::{ + dioxus_ssr_html, + serve::ServeConfig, + server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, +}; + +pub trait DioxusRouterExt { + fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn serve_dioxus_application( + self, + cfg: ServeConfig

, + ) -> Self; } -fn transform_rx(message: Result) -> Result { - let as_bytes = message.map_err(|_| LiveViewError::SendingFailed)?; +impl DioxusRouterExt for Router { + fn register_server_fns(self, server_fn_route: &'static str) -> Self { + let mut router = self; + for server_fn_path in DioxusServerFnRegistry::paths_registered() { + let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); + let full_route = format!("{server_fn_route}/{server_fn_path}"); + router = router.push(Router::with_path(&full_route).post(ServerFnHandler { + server_context: DioxusServerContext {}, + function: func, + })); + } + router + } - let msg = String::from_utf8(as_bytes.into_bytes()).map_err(|_| LiveViewError::SendingFailed)?; + fn serve_dioxus_application( + self, + cfg: ServeConfig

, + ) -> Self { + // Serve the dist folder and the index.html file + let serve_dir = StaticDir::new(["dist"]); - Ok(msg) + self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) + .push(Router::with_path("/").get(SSRHandler { cfg })) + .push(Router::with_path("<**path>").get(serve_dir)) + } } -async fn transform_tx(message: String) -> Result { - Ok(Message::text(message)) +struct SSRHandler { + cfg: ServeConfig

, +} + +#[async_trait] +impl Handler for SSRHandler

{ + async fn handle( + &self, + _req: &mut Request, + _depot: &mut Depot, + res: &mut Response, + _flow: &mut FlowCtrl, + ) { + res.write_body(dioxus_ssr_html(&self.cfg)).unwrap(); + } +} + +struct ServerFnHandler { + server_context: DioxusServerContext, + function: Arc, +} + +#[handler] +impl ServerFnHandler { + async fn handle(&self, req: &mut Request, _depot: &mut Depot, res: &mut Response) { + let Self { + server_context, + function, + } = self; + + let body = hyper::body::to_bytes(req.body_mut().unwrap()).await; + let Ok(body)=body else { + handle_error(body.err().unwrap(), res); + return; + }; + let headers = req.headers(); + + // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime + let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); + let function = function.clone(); + let server_context = server_context.clone(); + spawn_blocking({ + move || { + tokio::runtime::Runtime::new() + .expect("couldn't spawn runtime") + .block_on(async move { + let resp = function(server_context, &body).await; + + resp_tx.send(resp).unwrap(); + }) + } + }); + let result = resp_rx.await.unwrap(); + + match result { + Ok(serialized) => { + // if this is Accept: application/json then send a serialized JSON response + let accept_header = headers.get("Accept").and_then(|value| value.to_str().ok()); + if accept_header == Some("application/json") + || accept_header + == Some( + "application/\ + x-www-form-urlencoded", + ) + || accept_header == Some("application/cbor") + { + res.set_status_code(StatusCode::OK); + } + + match serialized { + Payload::Binary(data) => { + res.headers_mut() + .insert("Content-Type", HeaderValue::from_static("application/cbor")); + res.write_body(data).unwrap(); + } + Payload::Url(data) => { + res.headers_mut().insert( + "Content-Type", + HeaderValue::from_static( + "application/\ + x-www-form-urlencoded", + ), + ); + res.render(data); + } + Payload::Json(data) => { + res.headers_mut() + .insert("Content-Type", HeaderValue::from_static("application/json")); + res.render(data); + } + } + } + Err(err) => handle_error(err, res), + } + } +} + +fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { + let mut resp_err = Response::new(); + resp_err.set_status_code(StatusCode::INTERNAL_SERVER_ERROR); + resp_err.render(format!("Internal Server Error: {}", error)); + *res = resp_err; } From 0b80d32d187b6fe75352029a62366045e33b35c1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 30 Mar 2023 20:50:58 -0500 Subject: [PATCH 373/895] fix axum adapter --- packages/server/src/adapters/axum_adapter.rs | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index b7cc85e1c..9d99a697d 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -18,7 +18,10 @@ use crate::{ pub trait DioxusRouterExt { fn register_server_fns(self, server_fn_route: &'static str) -> Self; - fn serve_dioxus_application(self, cfg: ServeConfig) -> Self; + fn serve_dioxus_application( + self, + cfg: ServeConfig

, + ) -> Self; } impl DioxusRouterExt for Router { @@ -37,18 +40,24 @@ impl DioxusRouterExt for Router { router } - fn serve_dioxus_application(self, cfg: ServeConfig) -> Self { + fn serve_dioxus_application( + self, + cfg: ServeConfig

, + ) -> Self { use tower_http::services::ServeDir; // Serve the dist folder and the index.html file let serve_dir = ServeDir::new("dist"); self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) - .route("/", get(move || { - let rendered = dioxus_ssr_html(cfg); - async move { Full::from(rendered) } - })) - .fallback_service( serve_dir) + .route( + "/", + get(move || { + let rendered = dioxus_ssr_html(&cfg); + async move { Full::from(rendered) } + }), + ) + .fallback_service(serve_dir) } } From 5f7a6e2f3f75072e2dd76d5652597697e3a4593e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 31 Mar 2023 07:55:39 -0500 Subject: [PATCH 374/895] fix docs for the web cache setting --- packages/web/src/cfg.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/web/src/cfg.rs b/packages/web/src/cfg.rs index 7e47ed461..7483a7a8b 100644 --- a/packages/web/src/cfg.rs +++ b/packages/web/src/cfg.rs @@ -49,15 +49,16 @@ impl Config { /// Set the name of the element that Dioxus will use as the root. /// - /// This is akint to calling React.render() on the element with the specified name. + /// This is akin to calling React.render() on the element with the specified name. pub fn rootname(mut self, name: impl Into) -> Self { self.rootname = name.into(); self } - /// Set the name of the element that Dioxus will use as the root. + /// Sets a string cache for wasm bindgen to [intern](https://docs.rs/wasm-bindgen/0.2.84/wasm_bindgen/fn.intern.html). This can help reduce the time it takes for wasm bindgen to pass + /// strings from rust to javascript. This can significantly improve pefromance when passing strings to javascript, but can have a negative impact on startup time. /// - /// This is akint to calling React.render() on the element with the specified name. + /// > Currently this cache is only used when creating static elements and attributes. pub fn with_string_cache(mut self, cache: Vec) -> Self { self.cached_strings = cache; self From 976d4ab960e0dd5d0ac84c690add93da7508a147 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 31 Mar 2023 09:40:58 -0500 Subject: [PATCH 375/895] Add warp adapter --- Cargo.toml | 1 + packages/server/Cargo.toml | 3 +- .../examples/warp-hello-world/.gitignore | 2 + .../examples/warp-hello-world/Cargo.toml | 20 +++ .../examples/warp-hello-world/src/main.rs | 65 ++++++++ packages/server/src/adapters/mod.rs | 2 + packages/server/src/adapters/salvo_adapter.rs | 4 +- packages/server/src/adapters/warp_adapter.rs | 150 +++++++++++++++--- packages/server/src/lib.rs | 2 + 9 files changed, 225 insertions(+), 24 deletions(-) create mode 100644 packages/server/examples/warp-hello-world/.gitignore create mode 100644 packages/server/examples/warp-hello-world/Cargo.toml create mode 100644 packages/server/examples/warp-hello-world/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index bf2b4b8c4..f4ad80086 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ members = [ "packages/server/server-macro", "packages/server/examples/axum-hello-world", "packages/server/examples/salvo-hello-world", + "packages/server/examples/warp-hello-world", "docs/guide", ] diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index fc5f33c7f..ee0a826e9 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -11,6 +11,7 @@ server_macro = { path = "server-macro" } # warp warp = { version = "0.3.3", optional = true } +http-body = { version = "0.4.5", optional = true } # axum axum = { version = "0.6.1", optional = true } @@ -31,7 +32,7 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } [features] default = [] -warp = ["dep:warp"] +warp = ["dep:warp", "http-body"] axum = ["dep:axum", "tower-http", "hyper"] salvo = ["dep:salvo", "hyper"] ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] diff --git a/packages/server/examples/warp-hello-world/.gitignore b/packages/server/examples/warp-hello-world/.gitignore new file mode 100644 index 000000000..6047329c6 --- /dev/null +++ b/packages/server/examples/warp-hello-world/.gitignore @@ -0,0 +1,2 @@ +dist +target \ No newline at end of file diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml new file mode 100644 index 000000000..122eddf36 --- /dev/null +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "warp-hello-world" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } +dioxus = { path = "../../../dioxus" } +dioxus-server = { path = "../../" } +tokio = { version = "1.27.0", features = ["full"], optional = true } +serde = "1.0.159" +tracing-subscriber = "0.3.16" +tracing = "0.1.37" +warp = { version = "0.3.3", optional = true } + +[features] +ssr = ["warp", "tokio", "dioxus-server/ssr", "dioxus-server/warp"] +web = ["dioxus-web"] diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs new file mode 100644 index 000000000..2bac390e2 --- /dev/null +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -0,0 +1,65 @@ +//! Run with: +//! +//! ```sh +//! dioxus build --features web +//! cargo run --features ssr +//! ``` + +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + PostServerData::register().unwrap(); + GetServerData::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let routes = serve_dioxus_application( + ServeConfig::new(app, ()).head(r#"Hello World!"#), + ); + warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; + }); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + let text = use_state(cx, || "...".to_string()); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![text]; + async move { + if let Ok(data) = get_server_data().await { + println!("Client received: {}", data); + text.set(data.clone()); + post_server_data(data).await.unwrap(); + } + } + }, + "Run a server function" + } + "Server said: {text}" + }) +} + +#[server(PostServerData)] +async fn post_server_data(data: String) -> Result<(), ServerFnError> { + println!("Server received: {}", data); + + Ok(()) +} + +#[server(GetServerData)] +async fn get_server_data() -> Result { + Ok("Hello from the server!".to_string()) +} diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs index 41bb4a403..0c292bd8d 100644 --- a/packages/server/src/adapters/mod.rs +++ b/packages/server/src/adapters/mod.rs @@ -2,3 +2,5 @@ pub mod axum_adapter; #[cfg(feature = "salvo")] pub mod salvo_adapter; +#[cfg(feature = "warp")] +pub mod warp_adapter; diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 20edc9364..f381e0b4a 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -132,12 +132,12 @@ impl ServerFnHandler { x-www-form-urlencoded", ), ); - res.render(data); + res.write_body(data).unwrap(); } Payload::Json(data) => { res.headers_mut() .insert("Content-Type", HeaderValue::from_static("application/json")); - res.render(data); + res.write_body(data).unwrap(); } } } diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index e5c821ce3..2577de61f 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -1,28 +1,136 @@ -use crate::{LiveViewError, LiveViewSocket}; -use futures_util::{SinkExt, StreamExt}; -use warp::ws::{Message, WebSocket}; +use std::{error::Error, sync::Arc}; -/// Convert a warp websocket into a LiveViewSocket -/// -/// This is required to launch a LiveView app using the warp web framework -pub fn warp_socket(ws: WebSocket) -> impl LiveViewSocket { - ws.map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) +use server_fn::{Payload, ServerFunctionRegistry}; +use tokio::task::spawn_blocking; +use warp::{ + filters::BoxedFilter, + http::{Response, StatusCode}, + hyper::{body::Bytes, HeaderMap}, + path, Filter, Reply, +}; + +use crate::{ + dioxus_ssr_html, + serve::ServeConfig, + server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, +}; + +pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { + let mut filter: Option> = None; + for server_fn_path in DioxusServerFnRegistry::paths_registered() { + let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); + let full_route = format!("{server_fn_route}/{server_fn_path}") + .trim_start_matches('/') + .to_string(); + let route = path(full_route) + .and(warp::post()) + .and(warp::header::headers_cloned()) + .and(warp::body::bytes()) + .and_then(move |headers: HeaderMap, body| { + let func = func.clone(); + async move { server_fn_handler(DioxusServerContext {}, func, headers, body).await } + }) + .boxed(); + if let Some(boxed_filter) = filter.take() { + filter = Some(boxed_filter.or(route).unify().boxed()); + } else { + filter = Some(route.boxed()); + } + } + filter.expect("No server functions found") } -fn transform_rx(message: Result) -> Result { - // destructure the message into the buffer we got from warp - let msg = message - .map_err(|_| LiveViewError::SendingFailed)? - .into_bytes(); +pub fn serve_dioxus_application( + cfg: ServeConfig

, +) -> BoxedFilter<(impl Reply,)> { + // Serve the dist folder and the index.html file + let serve_dir = warp::fs::dir("./dist"); - // transform it back into a string, saving us the allocation - let msg = String::from_utf8(msg).map_err(|_| LiveViewError::SendingFailed)?; - - Ok(msg) + register_server_fns(cfg.server_fn_route.unwrap_or_default()) + .or(warp::path::end() + .and(warp::get()) + .map(move || warp::reply::html(dioxus_ssr_html(&cfg)))) + .or(serve_dir) + .boxed() } -async fn transform_tx(message: String) -> Result { - Ok(Message::text(message)) +#[derive(Debug)] +struct FailedToReadBody(String); + +impl warp::reject::Reject for FailedToReadBody {} + +#[derive(Debug)] +struct RecieveFailed(String); + +impl warp::reject::Reject for RecieveFailed {} + +async fn server_fn_handler( + server_context: DioxusServerContext, + function: Arc, + headers: HeaderMap, + body: Bytes, +) -> Result, warp::Rejection> { + // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime + let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); + spawn_blocking({ + move || { + tokio::runtime::Runtime::new() + .expect("couldn't spawn runtime") + .block_on(async { + let resp = match function(server_context, &body).await { + Ok(serialized) => { + // if this is Accept: application/json then send a serialized JSON response + let accept_header = + headers.get("Accept").and_then(|value| value.to_str().ok()); + let mut res = Response::builder(); + if accept_header == Some("application/json") + || accept_header + == Some( + "application/\ + x-www-form-urlencoded", + ) + || accept_header == Some("application/cbor") + { + res = res.status(StatusCode::OK); + } + + let resp = match serialized { + Payload::Binary(data) => res + .header("Content-Type", "application/cbor") + .body(Bytes::from(data)), + Payload::Url(data) => res + .header( + "Content-Type", + "application/\ + x-www-form-urlencoded", + ) + .body(Bytes::from(data)), + Payload::Json(data) => res + .header("Content-Type", "application/json") + .body(Bytes::from(data)), + }; + + Box::new(resp.unwrap()) + } + Err(e) => report_err(e), + }; + + if resp_tx.send(resp).is_err() { + eprintln!("Error sending response"); + } + }) + } + }); + resp_rx.await.map_err(|err| { + warp::reject::custom(RecieveFailed(format!("Failed to recieve response {err}"))) + }) +} + +fn report_err(e: E) -> Box { + Box::new( + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(format!("Error: {}", e)) + .unwrap(), + ) as Box } diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index e7559363a..1cdd2f786 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -11,6 +11,8 @@ pub mod prelude { pub use crate::adapters::axum_adapter::*; #[cfg(feature = "salvo")] pub use crate::adapters::salvo_adapter::*; + #[cfg(feature = "warp")] + pub use crate::adapters::warp_adapter::*; #[cfg(feature = "ssr")] pub use crate::serve::ServeConfig; pub use crate::server_fn::{DioxusServerContext, ServerFn}; From bfcb0f6eab33ed8f9ec2d9a9f0b36de51f257f70 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 31 Mar 2023 15:33:44 -0500 Subject: [PATCH 376/895] add an example illistrating intigration with the router --- Cargo.toml | 1 + packages/router/src/components/router.rs | 1 + packages/server/Cargo.toml | 2 + .../examples/axum-hello-world/Cargo.toml | 5 +- .../examples/axum-hello-world/src/main.rs | 2 + .../server/examples/axum-router/.gitignore | 2 + .../server/examples/axum-router/Cargo.toml | 21 +++ .../server/examples/axum-router/src/main.rs | 141 ++++++++++++++++++ .../examples/salvo-hello-world/Cargo.toml | 2 - .../examples/warp-hello-world/Cargo.toml | 2 - packages/server/src/adapters/axum_adapter.rs | 17 ++- packages/server/src/lib.rs | 53 +------ packages/server/src/render.rs | 92 ++++++++++++ packages/server/src/serve.rs | 8 - packages/ssr/src/renderer.rs | 6 +- 15 files changed, 283 insertions(+), 72 deletions(-) create mode 100644 packages/server/examples/axum-router/.gitignore create mode 100644 packages/server/examples/axum-router/Cargo.toml create mode 100644 packages/server/examples/axum-router/src/main.rs create mode 100644 packages/server/src/render.rs diff --git a/Cargo.toml b/Cargo.toml index f4ad80086..e2e427043 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ members = [ "packages/server/examples/axum-hello-world", "packages/server/examples/salvo-hello-world", "packages/server/examples/warp-hello-world", + "packages/server/examples/axum-router", "docs/guide", ] diff --git a/packages/router/src/components/router.rs b/packages/router/src/components/router.rs index 54131a13a..b027386c5 100644 --- a/packages/router/src/components/router.rs +++ b/packages/router/src/components/router.rs @@ -29,6 +29,7 @@ pub struct RouterProps<'a> { pub active_class: Option<&'a str>, /// Set the initial url. + #[props(!optional, into)] pub initial_url: Option, } diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index ee0a826e9..fa0e0592a 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -17,6 +17,7 @@ http-body = { version = "0.4.5", optional = true } axum = { version = "0.6.1", optional = true } tower-http = { version = "0.4.0", optional = true, features = ["fs"] } hyper = { version = "0.14.25", optional = true } +axum-macros = "0.3.7" # salvo salvo = { version = "0.37.7", optional = true, features = ["serve-static"] } @@ -29,6 +30,7 @@ log = "0.4.17" once_cell = "1.17.1" thiserror = "1.0.40" tokio = { version = "1.27.0", features = ["full"], optional = true } +object-pool = "0.5.4" [features] default = [] diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index 54aaf17d3..68da7a0be 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -8,13 +8,12 @@ edition = "2021" [dependencies] dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } dioxus = { path = "../../../dioxus" } +dioxus-router = { path = "../../../router" } dioxus-server = { path = "../../" } axum = { version = "0.6.12", optional = true } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" -tracing-subscriber = "0.3.16" -tracing = "0.1.37" [features] ssr = ["axum", "tokio", "dioxus-server/ssr", "dioxus-server/axum"] -web = ["dioxus-web"] +web = ["dioxus-web", "dioxus-router/web"] diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index 4d4ab5e78..b4bc76390 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -25,7 +25,9 @@ fn main() { axum::Router::new() .serve_dioxus_application( ServeConfig::new(app, ()).head(r#"Hello World!"#), + None, ) + .with_state(SSRState::default()) .into_make_service(), ) .await diff --git a/packages/server/examples/axum-router/.gitignore b/packages/server/examples/axum-router/.gitignore new file mode 100644 index 000000000..6047329c6 --- /dev/null +++ b/packages/server/examples/axum-router/.gitignore @@ -0,0 +1,2 @@ +dist +target \ No newline at end of file diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml new file mode 100644 index 000000000..d1d8ff81d --- /dev/null +++ b/packages/server/examples/axum-router/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "axum-router" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } +dioxus = { path = "../../../dioxus" } +dioxus-router = { path = "../../../router" } +dioxus-server = { path = "../../" } +axum = { version = "0.6.12", optional = true } +tokio = { version = "1.27.0", features = ["full"], optional = true } +serde = "1.0.159" +tower-http = { version = "0.4.0", features = ["fs"], optional = true } +http = { version = "0.2.9", optional = true } + +[features] +ssr = ["axum", "tokio", "dioxus-server/ssr", "dioxus-server/axum", "tower-http", "http"] +web = ["dioxus-web", "dioxus-router/web"] diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs new file mode 100644 index 000000000..8745aa7f1 --- /dev/null +++ b/packages/server/examples/axum-router/src/main.rs @@ -0,0 +1,141 @@ +//! Run with: +//! +//! ```sh +//! dioxus build --features web +//! cargo run --features ssr +//! ``` + +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_router::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_with_props( + App, + AppProps { route: None }, + dioxus_web::Config::new().hydrate(true), + ); + #[cfg(feature = "ssr")] + { + use axum::extract::State; + PostServerData::register().unwrap(); + GetServerData::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + use tower_http::services::ServeDir; + + // Serve the dist/assets folder with the javascript and WASM files created by the CLI + let serve_dir = ServeDir::new("dist/assets"); + + axum::Server::bind(&addr) + .serve( + axum::Router::new() + // Register server functions + .register_server_fns("") + // Serve the static assets folder + .nest_service("/assets", serve_dir) + // If the path is unknown, render the application + .fallback( + move |uri: http::uri::Uri, State(ssr_state): State| { + let rendered = ssr_state.render( + &ServeConfig::new( + App, + AppProps { + route: Some(format!("http://{addr}{uri}")), + }, + ) + .head(r#"Hello World!"#), + ); + async move { axum::body::Full::from(rendered) } + }, + ) + .with_state(SSRState::default()) + .into_make_service(), + ) + .await + .unwrap(); + }); + } +} + +#[derive(Clone, Debug, Props, PartialEq)] +struct AppProps { + route: Option, +} + +fn App(cx: Scope) -> Element { + cx.render(rsx! { + Router { + initial_url: cx.props.route.clone(), + + Route { to: "/blog", + Link { + to: "/", + "Go to counter" + } + table { + tbody { + for _ in 0..100 { + tr { + for _ in 0..100 { + td { "hello world??" } + } + } + } + } + } + }, + // Fallback + Route { to: "", + Counter {} + }, + } + }) +} + +fn Counter(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + let text = use_state(cx, || "...".to_string()); + + cx.render(rsx! { + Link { + to: "/blog", + "Go to blog" + } + div{ + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![text]; + async move { + if let Ok(data) = get_server_data().await { + println!("Client received: {}", data); + text.set(data.clone()); + post_server_data(data).await.unwrap(); + } + } + }, + "Run a server function" + } + "Server said: {text}" + } + }) +} + +#[server(PostServerData)] +async fn post_server_data(data: String) -> Result<(), ServerFnError> { + println!("Server received: {}", data); + + Ok(()) +} + +#[server(GetServerData)] +async fn get_server_data() -> Result { + Ok("Hello from the server!".to_string()) +} diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 1ebe56dfc..9c81ee2a2 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -11,8 +11,6 @@ dioxus = { path = "../../../dioxus" } dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" -tracing-subscriber = "0.3.16" -tracing = "0.1.37" salvo = { version = "0.37.9", optional = true } [features] diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index 122eddf36..7bb9aa23f 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -11,8 +11,6 @@ dioxus = { path = "../../../dioxus" } dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" -tracing-subscriber = "0.3.16" -tracing = "0.1.37" warp = { version = "0.3.3", optional = true } [features] diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 9d99a697d..5eaff9bfc 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -2,6 +2,7 @@ use std::{error::Error, sync::Arc}; use axum::{ body::{self, Body, BoxBody, Full}, + extract::{FromRef, State}, http::{HeaderMap, Request, Response, StatusCode}, response::IntoResponse, routing::{get, post}, @@ -11,7 +12,7 @@ use server_fn::{Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; use crate::{ - dioxus_ssr_html, + render::SSRState, serve::ServeConfig, server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, }; @@ -21,10 +22,15 @@ pub trait DioxusRouterExt { fn serve_dioxus_application( self, cfg: ServeConfig

, + server_fn_route: Option<&'static str>, ) -> Self; } -impl DioxusRouterExt for Router { +impl DioxusRouterExt for Router +where + SSRState: FromRef, + S: Send + Sync + Clone + 'static, +{ fn register_server_fns(self, server_fn_route: &'static str) -> Self { let mut router = self; for server_fn_path in DioxusServerFnRegistry::paths_registered() { @@ -43,17 +49,18 @@ impl DioxusRouterExt for Router { fn serve_dioxus_application( self, cfg: ServeConfig

, + server_fn_route: Option<&'static str>, ) -> Self { use tower_http::services::ServeDir; // Serve the dist folder and the index.html file let serve_dir = ServeDir::new("dist"); - self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) + self.register_server_fns(server_fn_route.unwrap_or_default()) .route( "/", - get(move || { - let rendered = dioxus_ssr_html(&cfg); + get(move |State(ssr_state): State| { + let rendered = ssr_state.render(&cfg); async move { Full::from(rendered) } }), ) diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 1cdd2f786..9141c7199 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -3,6 +3,8 @@ use dioxus_core::prelude::*; mod adapters; #[cfg(feature = "ssr")] +pub mod render; +#[cfg(feature = "ssr")] mod serve; mod server_fn; @@ -14,57 +16,10 @@ pub mod prelude { #[cfg(feature = "warp")] pub use crate::adapters::warp_adapter::*; #[cfg(feature = "ssr")] + pub use crate::render::*; + #[cfg(feature = "ssr")] pub use crate::serve::ServeConfig; pub use crate::server_fn::{DioxusServerContext, ServerFn}; pub use server_fn::{self, ServerFn as _, ServerFnError}; pub use server_macro::*; } - -#[cfg(feature = "ssr")] -fn dioxus_ssr_html(cfg: &serve::ServeConfig

) -> String { - use prelude::ServeConfig; - - let ServeConfig { - app, - application_name, - base_path, - head, - props, - .. - } = cfg; - - let application_name = application_name.unwrap_or("dioxus"); - - let mut vdom = VirtualDom::new_with_props(*app, props.clone()); - let _ = vdom.rebuild(); - let renderered = dioxus_ssr::pre_render(&vdom); - let base_path = base_path.unwrap_or("."); - let head = head.unwrap_or( - r#"Dioxus Application - - - "#, - ); - format!( - r#" - - - - {head} - - -

- {renderered} -
- - -"# - ) -} diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs new file mode 100644 index 000000000..5c15bd097 --- /dev/null +++ b/packages/server/src/render.rs @@ -0,0 +1,92 @@ +use std::fmt::Write; +use std::sync::Arc; + +use dioxus_core::VirtualDom; +use dioxus_ssr::Renderer; + +use crate::prelude::ServeConfig; + +fn dioxus_ssr_html(cfg: &ServeConfig

, renderer: &mut Renderer) -> String { + let ServeConfig { + app, + application_name, + base_path, + head, + props, + .. + } = cfg; + + let application_name = application_name.unwrap_or("dioxus"); + let mut vdom = VirtualDom::new_with_props(*app, props.clone()); + let _ = vdom.rebuild(); + let base_path = base_path.unwrap_or("."); + let head = head.unwrap_or( + r#"Dioxus Application + + + "#, + ); + + let mut html = String::new(); + + if let Err(err) = write!( + &mut html, + r#" + + + {head} + + +

"# + ) { + eprintln!("Failed to write to html: {}", err); + } + + let _ = renderer.render_to(&mut html, &vdom); + + if let Err(err) = write!( + &mut html, + r#"
+ + + "# + ) { + eprintln!("Failed to write to html: {}", err); + } + + html +} + +#[derive(Clone)] +pub struct SSRState { + // We keep a cache of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move + renderers: Arc>, +} + +impl Default for SSRState { + fn default() -> Self { + Self { + renderers: Arc::new(object_pool::Pool::new(10, pre_renderer)), + } + } +} + +impl SSRState { + pub fn render(&self, cfg: &ServeConfig

) -> String { + let mut renderer = self.renderers.pull(pre_renderer); + dioxus_ssr_html(cfg, &mut renderer) + } +} + +fn pre_renderer() -> Renderer { + let mut renderer = Renderer::default(); + renderer.pre_render = true; + renderer +} diff --git a/packages/server/src/serve.rs b/packages/server/src/serve.rs index 9cca17a6b..65f0871ae 100644 --- a/packages/server/src/serve.rs +++ b/packages/server/src/serve.rs @@ -5,7 +5,6 @@ pub struct ServeConfig { pub(crate) app: Component

, pub(crate) props: P, pub(crate) application_name: Option<&'static str>, - pub(crate) server_fn_route: Option<&'static str>, pub(crate) base_path: Option<&'static str>, pub(crate) head: Option<&'static str>, } @@ -17,7 +16,6 @@ impl ServeConfig

{ app, props, application_name: None, - server_fn_route: None, base_path: None, head: None, } @@ -29,12 +27,6 @@ impl ServeConfig

{ self } - /// Set the base route all server functions will be served under - pub fn server_fn_route(mut self, server_fn_route: &'static str) -> Self { - self.server_fn_route = Some(server_fn_route); - self - } - /// Set the path the WASM application will be served under pub fn base_path(mut self, base_path: &'static str) -> Self { self.base_path = Some(base_path); diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index 5b6fa8fb2..d9c312ac7 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -3,7 +3,7 @@ use crate::cache::StringCache; use dioxus_core::{prelude::*, AttributeValue, DynamicNode, RenderReturn}; use std::collections::HashMap; use std::fmt::Write; -use std::rc::Rc; +use std::sync::Arc; /// A virtualdom renderer that caches the templates it has seen for faster rendering #[derive(Default)] @@ -25,7 +25,7 @@ pub struct Renderer { pub skip_components: bool, /// A cache of templates that have been rendered - template_cache: HashMap<&'static str, Rc>, + template_cache: HashMap<&'static str, Arc>, } impl Renderer { @@ -67,7 +67,7 @@ impl Renderer { let entry = self .template_cache .entry(template.template.get().name) - .or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap())) + .or_insert_with(|| Arc::new(StringCache::from_template(template).unwrap())) .clone(); for segment in entry.segments.iter() { From 5ffdb4dbede3e8806566a0debd69d0442c8521a9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 31 Mar 2023 16:16:47 -0500 Subject: [PATCH 377/895] prefech wasm + JS by default --- .../server/examples/axum-router/src/main.rs | 15 ++++----- packages/server/src/render.rs | 31 +++++++++++++------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 8745aa7f1..0ae68d50e 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -41,15 +41,12 @@ fn main() { // If the path is unknown, render the application .fallback( move |uri: http::uri::Uri, State(ssr_state): State| { - let rendered = ssr_state.render( - &ServeConfig::new( - App, - AppProps { - route: Some(format!("http://{addr}{uri}")), - }, - ) - .head(r#"Hello World!"#), - ); + let rendered = ssr_state.render(&ServeConfig::new( + App, + AppProps { + route: Some(format!("http://{addr}{uri}")), + }, + )); async move { axum::body::Full::from(rendered) } }, ) diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 5c15bd097..872a6cffc 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -20,25 +20,36 @@ fn dioxus_ssr_html(cfg: &ServeConfig

, renderer: &mut Rend let mut vdom = VirtualDom::new_with_props(*app, props.clone()); let _ = vdom.rebuild(); let base_path = base_path.unwrap_or("."); - let head = head.unwrap_or( - r#"Dioxus Application - - - "#, - ); let mut html = String::new(); - if let Err(err) = write!( - &mut html, - r#" + let result = match head { + Some(head) => { + write!( + &mut html, + r#" {head}

"# - ) { + ) + } + None => { + write!( + &mut html, + r#"Dioxus Application + + + + + "# + ) + } + }; + + if let Err(err) = result { eprintln!("Failed to write to html: {}", err); } From 71ddd50963b9aae55386ba64936d217a9bf6b5b7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 1 Apr 2023 17:00:09 -0500 Subject: [PATCH 378/895] provide a nicer builder API --- .../examples/axum-hello-world/src/main.rs | 6 +-- .../server/examples/axum-router/src/main.rs | 17 ++++--- .../examples/salvo-hello-world/src/main.rs | 5 +- .../examples/warp-hello-world/src/main.rs | 4 +- packages/server/src/render.rs | 28 ++--------- packages/server/src/serve.rs | 47 ++++++++++++++++++- 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index b4bc76390..fc07c6fbb 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -23,11 +23,7 @@ fn main() { axum::Server::bind(&addr) .serve( axum::Router::new() - .serve_dioxus_application( - ServeConfig::new(app, ()).head(r#"Hello World!"#), - None, - ) - .with_state(SSRState::default()) + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) .into_make_service(), ) .await diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 0ae68d50e..53193859c 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -41,12 +41,15 @@ fn main() { // If the path is unknown, render the application .fallback( move |uri: http::uri::Uri, State(ssr_state): State| { - let rendered = ssr_state.render(&ServeConfig::new( - App, - AppProps { - route: Some(format!("http://{addr}{uri}")), - }, - )); + let rendered = ssr_state.render( + &ServeConfigBuilder::new( + App, + AppProps { + route: Some(format!("http://{addr}{uri}")), + }, + ) + .build(), + ); async move { axum::body::Full::from(rendered) } }, ) @@ -79,7 +82,7 @@ fn App(cx: Scope) -> Element { for _ in 0..100 { tr { for _ in 0..100 { - td { "hello world??" } + td { "hello world!" } } } } diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index cd8b80c51..f13668c5e 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -20,9 +20,8 @@ fn main() { tokio::runtime::Runtime::new() .unwrap() .block_on(async move { - let router = Router::new().serve_dioxus_application( - ServeConfig::new(app, ()).head(r#"Hello World!"#), - ); + let router = + Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); Server::new(TcpListener::bind("127.0.0.1:8080")) .serve(router) .await; diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 2bac390e2..87f91782a 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -19,9 +19,7 @@ fn main() { tokio::runtime::Runtime::new() .unwrap() .block_on(async move { - let routes = serve_dioxus_application( - ServeConfig::new(app, ()).head(r#"Hello World!"#), - ); + let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ())); warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; }); } diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 872a6cffc..cb752eaed 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -16,38 +16,20 @@ fn dioxus_ssr_html(cfg: &ServeConfig

, renderer: &mut Rend .. } = cfg; - let application_name = application_name.unwrap_or("dioxus"); let mut vdom = VirtualDom::new_with_props(*app, props.clone()); let _ = vdom.rebuild(); - let base_path = base_path.unwrap_or("."); let mut html = String::new(); - let result = match head { - Some(head) => { - write!( - &mut html, - r#" + let result = write!( + &mut html, + r#" {head} - - +

"# - ) - } - None => { - write!( - &mut html, - r#"Dioxus Application - - - - - "# - ) - } - }; + ); if let Err(err) = result { eprintln!("Failed to write to html: {}", err); diff --git a/packages/server/src/serve.rs b/packages/server/src/serve.rs index 65f0871ae..ed059f47f 100644 --- a/packages/server/src/serve.rs +++ b/packages/server/src/serve.rs @@ -1,15 +1,16 @@ use dioxus_core::Component; #[derive(Clone)] -pub struct ServeConfig { +pub struct ServeConfigBuilder { pub(crate) app: Component

, pub(crate) props: P, pub(crate) application_name: Option<&'static str>, pub(crate) base_path: Option<&'static str>, pub(crate) head: Option<&'static str>, + pub(crate) assets_path: Option<&'static str>, } -impl ServeConfig

{ +impl ServeConfigBuilder

{ /// Create a new ServeConfig pub fn new(app: Component

, props: P) -> Self { Self { @@ -18,6 +19,7 @@ impl ServeConfig

{ application_name: None, base_path: None, head: None, + assets_path: None, } } @@ -38,4 +40,45 @@ impl ServeConfig

{ self.head = Some(head); self } + + /// Set the path of the assets folder generated by the Dioxus CLI. (defaults to dist/assets) + pub fn assets_path(mut self, assets_path: &'static str) -> Self { + self.assets_path = Some(assets_path); + self + } + + /// Build the ServeConfig + pub fn build(self) -> ServeConfig

{ + let base_path = self.base_path.unwrap_or("."); + let application_name = self.application_name.unwrap_or("dioxus"); + ServeConfig { + app: self.app, + props: self.props, + application_name, + base_path, + head: self.head.map(String::from).unwrap_or(format!(r#"Dioxus Application + + + + + "#)), + assets_path: self.assets_path.unwrap_or("dist/assets"), + } + } +} + +#[derive(Clone)] +pub struct ServeConfig { + pub(crate) app: Component

, + pub(crate) props: P, + pub(crate) application_name: &'static str, + pub(crate) base_path: &'static str, + pub(crate) head: String, + pub(crate) assets_path: &'static str, +} + +impl From> for ServeConfig

{ + fn from(builder: ServeConfigBuilder

) -> Self { + builder.build() + } } From c6992c7032474eaeda4bb8371cf64d22dada2981 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 1 Apr 2023 17:00:12 -0500 Subject: [PATCH 379/895] make server function API more flexible --- packages/server/Cargo.toml | 3 +- packages/server/server-macro/Cargo.toml | 3 +- packages/server/server-macro/src/lib.rs | 14 ++-- packages/server/src/adapters/axum_adapter.rs | 81 +++++++++++++------ packages/server/src/adapters/salvo_adapter.rs | 69 ++++++++++++---- packages/server/src/adapters/warp_adapter.rs | 69 +++++++++++----- packages/server/src/lib.rs | 8 +- packages/server/src/server_context.rs | 35 ++++++++ packages/server/src/server_fn.rs | 3 +- 9 files changed, 209 insertions(+), 76 deletions(-) create mode 100644 packages/server/src/server_context.rs diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index fa0e0592a..2485a2529 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -server_fn = { version = "0.2.4", features = ["stable"] } +server_fn = { path = "D:/Users/Desktop/github/leptos/server_fn", features = ["stable"] } server_macro = { path = "server-macro" } # warp @@ -31,6 +31,7 @@ once_cell = "1.17.1" thiserror = "1.0.40" tokio = { version = "1.27.0", features = ["full"], optional = true } object-pool = "0.5.4" +anymap = "0.12.1" [features] default = [] diff --git a/packages/server/server-macro/Cargo.toml b/packages/server/server-macro/Cargo.toml index cb285f517..e5fb6523e 100644 --- a/packages/server/server-macro/Cargo.toml +++ b/packages/server/server-macro/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" [dependencies] quote = "1.0.26" -server_fn_macro = { version = "0.2.4", features = ["stable"] } +# server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "1e037ecb60965c7c55fd781fdc8de7863ffd102b", features = ["stable"] } +server_fn_macro = { path = "D:/Users/Desktop/github/leptos/server_fn_macro", features = ["stable"] } syn = { version = "1", features = ["full"] } [lib] diff --git a/packages/server/server-macro/src/lib.rs b/packages/server/server-macro/src/lib.rs index f2a2e1665..f6b4f92a2 100644 --- a/packages/server/server-macro/src/lib.rs +++ b/packages/server/server-macro/src/lib.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::ToTokens; use server_fn_macro::*; -/// Declares that a function is a [server function](leptos_server). This means that +/// Declares that a function is a [server function](dioxus_server). This means that /// its body will only run on the server, i.e., when the `ssr` feature is enabled. /// /// If you call a server function from the client (i.e., when the `csr` or `hydrate` features @@ -19,18 +19,18 @@ use server_fn_macro::*; /// work without WebAssembly, the encoding must be `"Url"`. /// /// The server function itself can take any number of arguments, each of which should be serializable -/// and deserializable with `serde`. Optionally, its first argument can be a Leptos [Scope](leptos_reactive::Scope), +/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](dioxus_server::prelude::DioxusServerContext), /// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other /// server-side context into the server function. /// /// ```ignore -/// # use leptos::*; use serde::{Serialize, Deserialize}; +/// # use dioxus_server::prelude::*; use serde::{Serialize, Deserialize}; /// # #[derive(Serialize, Deserialize)] /// # pub struct Post { } /// #[server(ReadPosts, "/api")] /// pub async fn read_posts(how_many: u8, query: String) -> Result, ServerFnError> { /// // do some work on the server to access the database -/// todo!() +/// todo!() /// } /// ``` /// @@ -42,7 +42,7 @@ use server_fn_macro::*; /// - **Server functions must return `Result`.** Even if the work being done /// inside the function body can’t fail, the processes of serialization/deserialization and the /// network call are fallible. -/// - **Return types must be [Serializable](leptos_reactive::Serializable).** +/// - **Return types must implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html).** /// This should be fairly obvious: we have to serialize arguments to send them to the server, and we /// need to deserialize the result to return it to the client. /// - **Arguments must be implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) @@ -50,8 +50,8 @@ use server_fn_macro::*; /// They are serialized as an `application/x-www-form-urlencoded` /// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor` /// using [`cbor`](https://docs.rs/cbor/latest/cbor/). -/// - **The [Scope](leptos_reactive::Scope) comes from the server.** Optionally, the first argument of a server function -/// can be a Leptos [Scope](leptos_reactive::Scope). This scope can be used to inject dependencies like the HTTP request +/// - **The [DioxusServerContext](dioxus_server::prelude::DioxusServerContext) comes from the server.** Optionally, the first argument of a server function +/// can be a [DioxusServerContext](dioxus_server::prelude::DioxusServerContext). This scope can be used to inject dependencies like the HTTP request /// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client. #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 5eaff9bfc..8fb98b6ec 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -2,7 +2,8 @@ use std::{error::Error, sync::Arc}; use axum::{ body::{self, Body, BoxBody, Full}, - extract::{FromRef, State}, + extract::State, + handler::Handler, http::{HeaderMap, Request, Response, StatusCode}, response::IntoResponse, routing::{get, post}, @@ -14,61 +15,89 @@ use tokio::task::spawn_blocking; use crate::{ render::SSRState, serve::ServeConfig, - server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, + server_context::DioxusServerContext, + server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; -pub trait DioxusRouterExt { +pub trait DioxusRouterExt { + fn register_server_fns_with_handler( + self, + server_fn_route: &'static str, + handler: impl Fn(Arc) -> H, + ) -> Self + where + H: Handler, + T: 'static, + S: Clone + Send + Sync + 'static; fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn serve_dioxus_application( self, - cfg: ServeConfig

, - server_fn_route: Option<&'static str>, + server_fn_route: &'static str, + cfg: impl Into>, ) -> Self; } -impl DioxusRouterExt for Router +impl DioxusRouterExt for Router where - SSRState: FromRef, S: Send + Sync + Clone + 'static, { - fn register_server_fns(self, server_fn_route: &'static str) -> Self { + fn register_server_fns_with_handler( + self, + server_fn_route: &'static str, + mut handler: impl FnMut(Arc) -> H, + ) -> Self + where + H: Handler, + T: 'static, + S: Clone + Send + Sync + 'static, + { let mut router = self; for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); let full_route = format!("{server_fn_route}/{server_fn_path}"); - router = router.route( - &full_route, - post(move |headers: HeaderMap, body: Request| async move { - server_fn_handler(DioxusServerContext {}, func.clone(), headers, body).await - }), - ); + router = router.route(&full_route, post(handler(func))); } router } + fn register_server_fns(self, server_fn_route: &'static str) -> Self { + self.register_server_fns_with_handler(server_fn_route, |func| { + move |headers: HeaderMap, body: Request| async move { + server_fn_handler(DioxusServerContext::default(), func.clone(), headers, body).await + } + }) + } + fn serve_dioxus_application( self, - cfg: ServeConfig

, - server_fn_route: Option<&'static str>, + server_fn_route: &'static str, + cfg: impl Into>, ) -> Self { use tower_http::services::ServeDir; - // Serve the dist folder and the index.html file - let serve_dir = ServeDir::new("dist"); + let cfg = cfg.into(); - self.register_server_fns(server_fn_route.unwrap_or_default()) - .route( + // Serve the dist folder and the index.html file + let serve_dir = ServeDir::new(cfg.assets_path); + + self.register_server_fns(server_fn_route) + .nest_service("/assets", serve_dir) + .route_service( "/", - get(move |State(ssr_state): State| { - let rendered = ssr_state.render(&cfg); - async move { Full::from(rendered) } - }), + get(render_handler).with_state((cfg, SSRState::default())), ) - .fallback_service(serve_dir) } } -async fn server_fn_handler( +async fn render_handler( + State((cfg, ssr_state)): State<(ServeConfig

, SSRState)>, +) -> impl IntoResponse { + let rendered = ssr_state.render(&cfg); + Full::from(rendered) +} + +pub async fn server_fn_handler( server_context: DioxusServerContext, function: Arc, headers: HeaderMap, diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index f381e0b4a..0d8a27b22 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -9,43 +9,65 @@ use server_fn::{Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; use crate::{ - dioxus_ssr_html, + prelude::DioxusServerContext, + prelude::SSRState, serve::ServeConfig, - server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, + server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; pub trait DioxusRouterExt { fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn register_server_fns_with_handler( + self, + server_fn_route: &'static str, + handler: impl Fn(Arc) -> H, + ) -> Self + where + H: Handler + 'static; fn serve_dioxus_application( self, - cfg: ServeConfig

, + server_fn_path: &'static str, + cfg: impl Into>, ) -> Self; } impl DioxusRouterExt for Router { - fn register_server_fns(self, server_fn_route: &'static str) -> Self { + fn register_server_fns_with_handler( + self, + server_fn_route: &'static str, + mut handler: impl FnMut(Arc) -> H, + ) -> Self + where + H: Handler + 'static, + { let mut router = self; for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); let full_route = format!("{server_fn_route}/{server_fn_path}"); - router = router.push(Router::with_path(&full_route).post(ServerFnHandler { - server_context: DioxusServerContext {}, - function: func, - })); + router = router.push(Router::with_path(&full_route).post(handler(func))); } router } + fn register_server_fns(self, server_fn_route: &'static str) -> Self { + self.register_server_fns_with_handler(|| ServerFnHandler { + server_context: DioxusServerContext::default(), + function: func, + }) + } + fn serve_dioxus_application( self, - cfg: ServeConfig

, + server_fn_route: &'static str, + cfg: impl Into>, ) -> Self { + let cfg = cfg.into(); // Serve the dist folder and the index.html file - let serve_dir = StaticDir::new(["dist"]); + let serve_dir = StaticDir::new([cfg.assets_path]); - self.register_server_fns(cfg.server_fn_route.unwrap_or_default()) + self.register_server_fns(server_fn_route) .push(Router::with_path("/").get(SSRHandler { cfg })) - .push(Router::with_path("<**path>").get(serve_dir)) + .push(Router::with_path("assets/<**path>").get(serve_dir)) } } @@ -58,19 +80,36 @@ impl Handler for SSRHandler

{ async fn handle( &self, _req: &mut Request, - _depot: &mut Depot, + depot: &mut Depot, res: &mut Response, _flow: &mut FlowCtrl, ) { - res.write_body(dioxus_ssr_html(&self.cfg)).unwrap(); + // Get the SSR renderer from the depot or create a new one if it doesn't exist + let renderer_pool = if let Some(renderer) = depot.obtain::() { + renderer.clone() + } else { + let renderer = SSRState::default(); + depot.inject(renderer.clone()); + renderer + }; + res.write_body(renderer_pool.render(&self.cfg)).unwrap(); } } -struct ServerFnHandler { +pub struct ServerFnHandler { server_context: DioxusServerContext, function: Arc, } +impl ServerFnHandler { + pub fn new(server_context: DioxusServerContext, function: Arc) -> Self { + Self { + server_context, + function, + } + } +} + #[handler] impl ServerFnHandler { async fn handle(&self, req: &mut Request, _depot: &mut Depot, res: &mut Response) { diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 2577de61f..00ebb38fa 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -10,50 +10,75 @@ use warp::{ }; use crate::{ - dioxus_ssr_html, + prelude::{DioxusServerContext, SSRState}, serve::ServeConfig, - server_fn::{DioxusServerContext, DioxusServerFnRegistry, ServerFnTraitObj}, + server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; -pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { - let mut filter: Option> = None; +pub fn register_server_fns_with_handler( + server_fn_route: &'static str, + mut handler: H, +) -> BoxedFilter<(R,)> +where + H: FnMut(String, Arc) -> F, + F: Filter + Send + Sync + 'static, + F::Extract: Send, + R: Reply + 'static, +{ + let mut filter: Option> = None; for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); let full_route = format!("{server_fn_route}/{server_fn_path}") .trim_start_matches('/') .to_string(); - let route = path(full_route) - .and(warp::post()) - .and(warp::header::headers_cloned()) - .and(warp::body::bytes()) - .and_then(move |headers: HeaderMap, body| { - let func = func.clone(); - async move { server_fn_handler(DioxusServerContext {}, func, headers, body).await } - }) - .boxed(); + let route = handler(full_route, func.clone()).boxed(); if let Some(boxed_filter) = filter.take() { filter = Some(boxed_filter.or(route).unify().boxed()); } else { - filter = Some(route.boxed()); + filter = Some(route); } } filter.expect("No server functions found") } -pub fn serve_dioxus_application( - cfg: ServeConfig

, -) -> BoxedFilter<(impl Reply,)> { - // Serve the dist folder and the index.html file - let serve_dir = warp::fs::dir("./dist"); +pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { + register_server_fns_with_handler(server_fn_route, |full_route, func| { + path(full_route) + .and(warp::post()) + .and(warp::header::headers_cloned()) + .and(warp::body::bytes()) + .and_then(move |headers: HeaderMap, body| { + let func = func.clone(); + async move { + server_fn_handler(DioxusServerContext::default(), func, headers, body).await + } + }) + }) +} - register_server_fns(cfg.server_fn_route.unwrap_or_default()) +pub fn serve_dioxus_application( + server_fn_route: &'static str, + cfg: impl Into>, +) -> BoxedFilter<(impl Reply,)> { + let cfg = cfg.into(); + // Serve the dist folder and the index.html file + let serve_dir = warp::fs::dir(cfg.assets_path); + + register_server_fns(server_fn_route) .or(warp::path::end() .and(warp::get()) - .map(move || warp::reply::html(dioxus_ssr_html(&cfg)))) - .or(serve_dir) + .and(with_ssr_state()) + .map(move |renderer: SSRState| warp::reply::html(renderer.render(&cfg)))) + .or(warp::path("assets").and(serve_dir)) .boxed() } +fn with_ssr_state() -> impl Filter + Clone +{ + let renderer = SSRState::default(); + warp::any().map(move || renderer.clone()) +} + #[derive(Debug)] struct FailedToReadBody(String); diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 9141c7199..a9c8e4939 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -6,6 +6,7 @@ mod adapters; pub mod render; #[cfg(feature = "ssr")] mod serve; +mod server_context; mod server_fn; pub mod prelude { @@ -18,8 +19,11 @@ pub mod prelude { #[cfg(feature = "ssr")] pub use crate::render::*; #[cfg(feature = "ssr")] - pub use crate::serve::ServeConfig; - pub use crate::server_fn::{DioxusServerContext, ServerFn}; + pub use crate::serve::{ServeConfig, ServeConfigBuilder}; + pub use crate::server_context::DioxusServerContext; + pub use crate::server_fn::ServerFn; + #[cfg(feature = "ssr")] + pub use crate::server_fn::ServerFnTraitObj; pub use server_fn::{self, ServerFn as _, ServerFnError}; pub use server_macro::*; } diff --git a/packages/server/src/server_context.rs b/packages/server/src/server_context.rs new file mode 100644 index 000000000..427ee21f8 --- /dev/null +++ b/packages/server/src/server_context.rs @@ -0,0 +1,35 @@ +use std::sync::{Arc, PoisonError, RwLock, RwLockWriteGuard}; + +use anymap::{any::Any, Map}; + +type SendSyncAnyMap = Map; + +/// A shared context for server functions. This allows you to pass data between your server and the server functions like authentication session data. +#[derive(Clone)] +pub struct DioxusServerContext { + shared_context: Arc>, +} + +impl Default for DioxusServerContext { + fn default() -> Self { + Self { + shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), + } + } +} + +impl DioxusServerContext { + pub fn get(&self) -> Option { + self.shared_context.read().ok()?.get::().cloned() + } + + pub fn insert( + &mut self, + value: T, + ) -> Result<(), PoisonError>> { + self.shared_context + .write() + .map(|mut map| map.insert(value)) + .map(|_| ()) + } +} diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs index 2f000adda..7170d61de 100644 --- a/packages/server/src/server_fn.rs +++ b/packages/server/src/server_fn.rs @@ -1,5 +1,4 @@ -#[derive(Clone)] -pub struct DioxusServerContext {} +use crate::server_context::DioxusServerContext; #[cfg(any(feature = "ssr", doc))] pub type ServerFnTraitObj = server_fn::ServerFnTraitObj; From 6a51f8998d8c012454122e4b7afbb84d2238d1f3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 1 Apr 2023 17:05:44 -0500 Subject: [PATCH 380/895] simplify server package features --- packages/server/Cargo.toml | 6 +++--- packages/server/examples/axum-hello-world/Cargo.toml | 3 ++- packages/server/examples/axum-hello-world/src/main.rs | 2 +- packages/server/examples/axum-router/Cargo.toml | 3 ++- packages/server/examples/axum-router/src/main.rs | 2 +- packages/server/examples/salvo-hello-world/Cargo.toml | 3 ++- packages/server/examples/salvo-hello-world/src/main.rs | 2 +- packages/server/examples/warp-hello-world/Cargo.toml | 3 ++- packages/server/examples/warp-hello-world/src/main.rs | 2 +- 9 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 2485a2529..5828875be 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -35,7 +35,7 @@ anymap = "0.12.1" [features] default = [] -warp = ["dep:warp", "http-body"] -axum = ["dep:axum", "tower-http", "hyper"] -salvo = ["dep:salvo", "hyper"] +warp = ["dep:warp", "http-body", "ssr"] +axum = ["dep:axum", "tower-http", "hyper", "ssr"] +salvo = ["dep:salvo", "hyper", "ssr"] ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index 68da7a0be..ed466e6e1 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -15,5 +15,6 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" [features] -ssr = ["axum", "tokio", "dioxus-server/ssr", "dioxus-server/axum"] +default = ["web"] +ssr = ["axum", "tokio", "dioxus-server/axum"] web = ["dioxus-web", "dioxus-router/web"] diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index fc07c6fbb..899247af5 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -2,7 +2,7 @@ //! //! ```sh //! dioxus build --features web -//! cargo run --features ssr +//! cargo run --features ssr --no-default-features //! ``` #![allow(non_snake_case)] diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml index d1d8ff81d..297aa6726 100644 --- a/packages/server/examples/axum-router/Cargo.toml +++ b/packages/server/examples/axum-router/Cargo.toml @@ -17,5 +17,6 @@ tower-http = { version = "0.4.0", features = ["fs"], optional = true } http = { version = "0.2.9", optional = true } [features] -ssr = ["axum", "tokio", "dioxus-server/ssr", "dioxus-server/axum", "tower-http", "http"] +default = ["web"] +ssr = ["axum", "tokio", "dioxus-server/axum", "tower-http", "http"] web = ["dioxus-web", "dioxus-router/web"] diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 53193859c..2afa4a481 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -2,7 +2,7 @@ //! //! ```sh //! dioxus build --features web -//! cargo run --features ssr +//! cargo run --features ssr --no-default-features //! ``` #![allow(non_snake_case)] diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 9c81ee2a2..4633eaafc 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -14,5 +14,6 @@ serde = "1.0.159" salvo = { version = "0.37.9", optional = true } [features] -ssr = ["salvo", "tokio", "dioxus-server/ssr", "dioxus-server/salvo"] +default = ["web"] +ssr = ["salvo", "tokio", "dioxus-server/salvo"] web = ["dioxus-web"] diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index f13668c5e..d1e654fee 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -2,7 +2,7 @@ //! //! ```sh //! dioxus build --features web -//! cargo run --features ssr +//! cargo run --features ssr --no-default-features //! ``` #![allow(non_snake_case)] diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index 7bb9aa23f..86ac2da5b 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -14,5 +14,6 @@ serde = "1.0.159" warp = { version = "0.3.3", optional = true } [features] -ssr = ["warp", "tokio", "dioxus-server/ssr", "dioxus-server/warp"] +default = ["web"] +ssr = ["warp", "tokio", "dioxus-server/warp"] web = ["dioxus-web"] diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 87f91782a..51a627d16 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -2,7 +2,7 @@ //! //! ```sh //! dioxus build --features web -//! cargo run --features ssr +//! cargo run --features ssr --no-default-features //! ``` #![allow(non_snake_case)] From 1cc4260f70c4ed0388f2e8f15ff3bd22d4159328 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 1 Apr 2023 20:15:10 -0500 Subject: [PATCH 381/895] more resilient keyboard event deserialization --- packages/html/src/events/keyboard.rs | 39 +++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/html/src/events/keyboard.rs b/packages/html/src/events/keyboard.rs index ee803d948..d00dcf8d2 100644 --- a/packages/html/src/events/keyboard.rs +++ b/packages/html/src/events/keyboard.rs @@ -5,6 +5,16 @@ use std::convert::TryInto; use std::fmt::{Debug, Formatter}; use std::str::FromStr; +#[cfg(feature = "serialize")] +fn resilient_deserialize_code<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::Deserialize; + // If we fail to deserialize the code for any reason, just return Unidentified instead of failing. + Ok(Code::deserialize(deserializer).unwrap_or(Code::Unidentified)) +} + pub type KeyboardEvent = Event; #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, PartialEq, Eq)] @@ -27,6 +37,10 @@ pub struct KeyboardData { pub key_code: KeyCode, /// the physical key on the keyboard + #[cfg_attr( + feature = "serialize", + serde(deserialize_with = "resilient_deserialize_code") + )] code: Code, /// Indicate if the `alt` modifier key was pressed during this keyboard event @@ -102,7 +116,7 @@ impl KeyboardData { /// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout. pub fn key(&self) -> Key { #[allow(deprecated)] - FromStr::from_str(&self.key).expect("could not parse") + FromStr::from_str(&self.key).unwrap_or(Key::Unidentified) } /// A physical key on the keyboard (as opposed to the character generated by pressing the key). In other words, this property returns a value that isn't altered by keyboard layout or the state of the modifier keys. @@ -158,10 +172,24 @@ impl Debug for KeyboardData { } } -#[cfg_attr( - feature = "serialize", - derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr) -)] +#[cfg(feature = "serialize")] +impl<'de> serde::Deserialize<'de> for KeyCode { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // We could be deserializing a unicode character, so we need to use u64 even if the output only takes u8 + let value = u64::deserialize(deserializer)?; + + if let Ok(smaller_uint) = value.try_into() { + Ok(KeyCode::from_raw_code(smaller_uint)) + } else { + Ok(KeyCode::Unknown) + } + } +} + +#[cfg_attr(feature = "serialize", derive(serde_repr::Serialize_repr))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(u8)] pub enum KeyCode { @@ -525,7 +553,6 @@ pub enum KeyCode { // kanji, = 244 // unlock trackpad (Chrome/Edge), = 251 // toggle touchpad, = 255 - #[cfg_attr(feature = "serialize", serde(other))] Unknown, } From f96425e4259ab2b0b881af0faf1f3ecbd3da1dd2 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 2 Apr 2023 15:07:51 -0500 Subject: [PATCH 382/895] collect templates for hot reloading --- packages/server/Cargo.toml | 8 ++- packages/server/src/render.rs | 114 ++++++++++++++++++++-------------- 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 5828875be..086448ca1 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# server functions server_fn = { path = "D:/Users/Desktop/github/leptos/server_fn", features = ["stable"] } server_macro = { path = "server-macro" } @@ -23,6 +24,7 @@ axum-macros = "0.3.7" salvo = { version = "0.37.7", optional = true, features = ["serve-static"] } serde = "1.0.159" +# Dioxus + SSR dioxus-core = { path = "../core", version = "^0.3.0" } dioxus-ssr = { path = "../ssr", version = "^0.3.0", optional = true } @@ -33,8 +35,12 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } object-pool = "0.5.4" anymap = "0.12.1" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +dioxus-hot-reload = { path = "../hot-reload" } + [features] -default = [] +default = ["hot-reload"] +hot-reload = [] warp = ["dep:warp", "http-body", "ssr"] axum = ["dep:axum", "tower-http", "hyper", "ssr"] salvo = ["dep:salvo", "hyper", "ssr"] diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index cb752eaed..bf8c12854 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -6,40 +6,82 @@ use dioxus_ssr::Renderer; use crate::prelude::ServeConfig; -fn dioxus_ssr_html(cfg: &ServeConfig

, renderer: &mut Renderer) -> String { - let ServeConfig { - app, - application_name, - base_path, - head, - props, - .. - } = cfg; +#[derive(Clone)] +pub struct SSRState { + // We keep a cache of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move + renderers: Arc>, + #[cfg(all(debug_assertions, feature = "hot-reload"))] + // The cache of all templates that have been modified since the last time we checked + templates: Arc>>>, +} - let mut vdom = VirtualDom::new_with_props(*app, props.clone()); - let _ = vdom.rebuild(); +impl Default for SSRState { + fn default() -> Self { + #[cfg(all(debug_assertions, feature = "hot-reload"))] + let templates = { + let templates = Arc::new(std::sync::RwLock::new(std::collections::HashSet::new())); + dioxus_hot_reload::connect({ + let templates = templates.clone(); + move |msg| match msg { + dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { + if let Ok(mut templates) = templates.write() { + templates.insert(template); + } + } + dioxus_hot_reload::HotReloadMsg::Shutdown => { + std::process::exit(0); + } + } + }); + templates + }; - let mut html = String::new(); + Self { + renderers: Arc::new(object_pool::Pool::new(10, pre_renderer)), + #[cfg(all(debug_assertions, feature = "hot-reload"))] + templates, + } + } +} - let result = write!( - &mut html, - r#" +impl SSRState { + pub fn render(&self, cfg: &ServeConfig

) -> String { + let ServeConfig { + app, + application_name, + base_path, + head, + props, + .. + } = cfg; + + let mut vdom = VirtualDom::new_with_props(*app, props.clone()); + + let _ = vdom.rebuild(); + + let mut renderer = self.renderers.pull(pre_renderer); + + let mut html = String::new(); + + let result = write!( + &mut html, + r#" {head}

"# - ); + ); - if let Err(err) = result { - eprintln!("Failed to write to html: {}", err); - } + if let Err(err) = result { + eprintln!("Failed to write to html: {}", err); + } - let _ = renderer.render_to(&mut html, &vdom); + let _ = renderer.render_to(&mut html, &vdom); - if let Err(err) = write!( - &mut html, - r#"
+ if let Err(err) = write!( + &mut html, + r#"
"# - ) { - eprintln!("Failed to write to html: {}", err); - } - - html -} - -#[derive(Clone)] -pub struct SSRState { - // We keep a cache of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move - renderers: Arc>, -} - -impl Default for SSRState { - fn default() -> Self { - Self { - renderers: Arc::new(object_pool::Pool::new(10, pre_renderer)), + ) { + eprintln!("Failed to write to html: {}", err); } - } -} -impl SSRState { - pub fn render(&self, cfg: &ServeConfig

) -> String { - let mut renderer = self.renderers.pull(pre_renderer); - dioxus_ssr_html(cfg, &mut renderer) + html } } From 9877dd7ed8928a2c5d08b546a54c93b26204c287 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 2 Apr 2023 16:18:15 -0500 Subject: [PATCH 383/895] parse and inject pre rendered content to work with trunk --- packages/server/src/adapters/axum_adapter.rs | 48 ++++++++-- packages/server/src/adapters/salvo_adapter.rs | 36 +++++++- packages/server/src/adapters/warp_adapter.rs | 2 +- packages/server/src/render.rs | 39 +------- packages/server/src/serve.rs | 92 ++++++++++++------- 5 files changed, 132 insertions(+), 85 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 8fb98b6ec..75c736731 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -70,23 +70,51 @@ where } fn serve_dioxus_application( - self, + mut self, server_fn_route: &'static str, cfg: impl Into>, ) -> Self { - use tower_http::services::ServeDir; + use tower_http::services::{ServeDir, ServeFile}; let cfg = cfg.into(); - // Serve the dist folder and the index.html file - let serve_dir = ServeDir::new(cfg.assets_path); - - self.register_server_fns(server_fn_route) - .nest_service("/assets", serve_dir) - .route_service( - "/", - get(render_handler).with_state((cfg, SSRState::default())), + // Serve all files in dist folder except index.html + let dir = std::fs::read_dir(cfg.assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &cfg.assets_path, e ) + }); + + for entry in dir.flatten() { + let path = entry.path(); + if path.ends_with("index.html") { + continue; + } + let route = path + .strip_prefix(&cfg.assets_path) + .unwrap() + .iter() + .map(|segment| { + segment.to_str().unwrap_or_else(|| { + panic!("Failed to convert path segment {:?} to string", segment) + }) + }) + .collect::>() + .join("/"); + let route = format!("/{}", route); + if path.is_dir() { + self = self.nest_service(&route, ServeDir::new(path)); + } else { + self = self.nest_service(&route, ServeFile::new(path)); + } + } + + // Add server functions and render index.html + self.register_server_fns(server_fn_route).route( + "/", + get(render_handler).with_state((cfg, SSRState::default())), + ) } } diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 0d8a27b22..f3bbd5f43 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -50,24 +50,50 @@ impl DioxusRouterExt for Router { } fn register_server_fns(self, server_fn_route: &'static str) -> Self { - self.register_server_fns_with_handler(|| ServerFnHandler { + self.register_server_fns_with_handler(server_fn_route, |func| ServerFnHandler { server_context: DioxusServerContext::default(), function: func, }) } fn serve_dioxus_application( - self, + mut self, server_fn_route: &'static str, cfg: impl Into>, ) -> Self { let cfg = cfg.into(); - // Serve the dist folder and the index.html file - let serve_dir = StaticDir::new([cfg.assets_path]); + + // Serve all files in dist folder except index.html + let dir = std::fs::read_dir(cfg.assets_path).unwrap_or_else(|e| { + panic!( + "Couldn't read assets directory at {:?}: {}", + &cfg.assets_path, e + ) + }); + + for entry in dir.flatten() { + let path = entry.path(); + if path.ends_with("index.html") { + continue; + } + let serve_dir = StaticDir::new([path.clone()]); + let route = path + .strip_prefix(&cfg.assets_path) + .unwrap() + .iter() + .map(|segment| { + segment.to_str().unwrap_or_else(|| { + panic!("Failed to convert path segment {:?} to string", segment) + }) + }) + .collect::>() + .join("/"); + let route = format!("/{}/<**path>", route); + self = self.push(Router::with_path(route).get(serve_dir)) + } self.register_server_fns(server_fn_route) .push(Router::with_path("/").get(SSRHandler { cfg })) - .push(Router::with_path("assets/<**path>").get(serve_dir)) } } diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 00ebb38fa..82d1c382f 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -69,7 +69,7 @@ pub fn serve_dioxus_application( .and(warp::get()) .and(with_ssr_state()) .map(move |renderer: SSRState| warp::reply::html(renderer.render(&cfg)))) - .or(warp::path("assets").and(serve_dir)) + .or(serve_dir) .boxed() } diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index bf8c12854..f6582d6a7 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -1,4 +1,3 @@ -use std::fmt::Write; use std::sync::Arc; use dioxus_core::VirtualDom; @@ -47,12 +46,7 @@ impl Default for SSRState { impl SSRState { pub fn render(&self, cfg: &ServeConfig

) -> String { let ServeConfig { - app, - application_name, - base_path, - head, - props, - .. + app, props, index, .. } = cfg; let mut vdom = VirtualDom::new_with_props(*app, props.clone()); @@ -63,38 +57,11 @@ impl SSRState { let mut html = String::new(); - let result = write!( - &mut html, - r#" - - - {head} - -

"# - ); - - if let Err(err) = result { - eprintln!("Failed to write to html: {}", err); - } + html += &index.pre_main; let _ = renderer.render_to(&mut html, &vdom); - if let Err(err) = write!( - &mut html, - r#"
- - - "# - ) { - eprintln!("Failed to write to html: {}", err); - } + html += &index.post_main; html } diff --git a/packages/server/src/serve.rs b/packages/server/src/serve.rs index ed059f47f..6284a6f1b 100644 --- a/packages/server/src/serve.rs +++ b/packages/server/src/serve.rs @@ -1,12 +1,15 @@ +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; + use dioxus_core::Component; #[derive(Clone)] pub struct ServeConfigBuilder { pub(crate) app: Component

, pub(crate) props: P, - pub(crate) application_name: Option<&'static str>, - pub(crate) base_path: Option<&'static str>, - pub(crate) head: Option<&'static str>, + pub(crate) root_id: Option<&'static str>, + pub(crate) index_path: Option<&'static str>, pub(crate) assets_path: Option<&'static str>, } @@ -16,32 +19,25 @@ impl ServeConfigBuilder

{ Self { app, props, - application_name: None, - base_path: None, - head: None, + root_id: None, + index_path: None, assets_path: None, } } - /// Set the application name matching the name in the Dioxus.toml file used to build the application - pub fn application_name(mut self, application_name: &'static str) -> Self { - self.application_name = Some(application_name); + /// Set the path of the index.html file to be served. (defaults to {assets_path}/index.html) + pub fn index_path(mut self, index_path: &'static str) -> Self { + self.index_path = Some(index_path); self } - /// Set the path the WASM application will be served under - pub fn base_path(mut self, base_path: &'static str) -> Self { - self.base_path = Some(base_path); + /// Set the id of the root element in the index.html file to place the prerendered content into. (defaults to main) + pub fn root_id(mut self, root_id: &'static str) -> Self { + self.root_id = Some(root_id); self } - /// Set the head content to be included in the HTML document served - pub fn head(mut self, head: &'static str) -> Self { - self.head = Some(head); - self - } - - /// Set the path of the assets folder generated by the Dioxus CLI. (defaults to dist/assets) + /// Set the path of the assets folder generated by the Dioxus CLI. (defaults to dist) pub fn assets_path(mut self, assets_path: &'static str) -> Self { self.assets_path = Some(assets_path); self @@ -49,31 +45,61 @@ impl ServeConfigBuilder

{ /// Build the ServeConfig pub fn build(self) -> ServeConfig

{ - let base_path = self.base_path.unwrap_or("."); - let application_name = self.application_name.unwrap_or("dioxus"); + let assets_path = self.assets_path.unwrap_or("dist"); + + let index_path = self + .index_path + .map(PathBuf::from) + .unwrap_or_else(|| format!("{assets_path}/index.html").into()); + + let root_id = self.root_id.unwrap_or("main"); + + let index = load_index_html(index_path, root_id); + ServeConfig { app: self.app, props: self.props, - application_name, - base_path, - head: self.head.map(String::from).unwrap_or(format!(r#"Dioxus Application - - - - - "#)), - assets_path: self.assets_path.unwrap_or("dist/assets"), + index, + assets_path, } } } +fn load_index_html(path: PathBuf, root_id: &'static str) -> IndexHtml { + let mut file = File::open(path).expect("Failed to find index.html. Make sure the index_path is set correctly and the WASM application has been built."); + + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Failed to read index.html"); + + 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 (pre_main, post_main) = ( + pre_main.to_string() + &format!("id=\"{root_id}\"") + post_main.0 + ">", + post_main.1.to_string(), + ); + + IndexHtml { + pre_main, + post_main, + } +} + +#[derive(Clone)] +pub(crate) struct IndexHtml { + pub(crate) pre_main: String, + pub(crate) post_main: String, +} + #[derive(Clone)] pub struct ServeConfig { pub(crate) app: Component

, pub(crate) props: P, - pub(crate) application_name: &'static str, - pub(crate) base_path: &'static str, - pub(crate) head: String, + pub(crate) index: IndexHtml, pub(crate) assets_path: &'static str, } From 7214130c4040873c3f1ee17ded1d5afb8a01f6c7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 2 Apr 2023 17:45:28 -0500 Subject: [PATCH 384/895] hot reloading intigration --- packages/server/Cargo.toml | 10 ++- packages/server/src/adapters/axum_adapter.rs | 71 +++++++++++++-- packages/server/src/adapters/salvo_adapter.rs | 87 ++++++++++++++++++- packages/server/src/adapters/warp_adapter.rs | 69 ++++++++++++++- packages/server/src/hot_reload.rs | 46 ++++++++++ packages/server/src/lib.rs | 2 + packages/server/src/render.rs | 24 ----- 7 files changed, 274 insertions(+), 35 deletions(-) create mode 100644 packages/server/src/hot_reload.rs diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 086448ca1..563912754 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -15,13 +15,13 @@ warp = { version = "0.3.3", optional = true } http-body = { version = "0.4.5", optional = true } # axum -axum = { version = "0.6.1", optional = true } +axum = { version = "0.6.1", features = ["ws"], optional = true } tower-http = { version = "0.4.0", optional = true, features = ["fs"] } hyper = { version = "0.14.25", optional = true } axum-macros = "0.3.7" # salvo -salvo = { version = "0.37.7", optional = true, features = ["serve-static"] } +salvo = { version = "0.37.7", optional = true, features = ["serve-static", "ws"] } serde = "1.0.159" # Dioxus + SSR @@ -35,12 +35,16 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } object-pool = "0.5.4" anymap = "0.12.1" +serde_json = { version = "1.0.95", optional = true } +tokio-stream = { version = "0.1.12", features = ["sync"], optional = true } +futures-util = { version = "0.3.28", optional = true } + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] dioxus-hot-reload = { path = "../hot-reload" } [features] default = ["hot-reload"] -hot-reload = [] +hot-reload = ["serde_json", "tokio-stream", "futures-util"] warp = ["dep:warp", "http-body", "ssr"] axum = ["dep:axum", "tower-http", "hyper", "ssr"] salvo = ["dep:salvo", "hyper", "ssr"] diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 75c736731..9fbcd5893 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -2,7 +2,7 @@ use std::{error::Error, sync::Arc}; use axum::{ body::{self, Body, BoxBody, Full}, - extract::State, + extract::{State, WebSocketUpgrade}, handler::Handler, http::{HeaderMap, Request, Response, StatusCode}, response::IntoResponse, @@ -36,6 +36,8 @@ pub trait DioxusRouterExt { server_fn_route: &'static str, cfg: impl Into>, ) -> Self; + + fn connect_hot_reload(self) -> Self; } impl DioxusRouterExt for Router @@ -92,7 +94,7 @@ where continue; } let route = path - .strip_prefix(&cfg.assets_path) + .strip_prefix(cfg.assets_path) .unwrap() .iter() .map(|segment| { @@ -111,10 +113,26 @@ where } // Add server functions and render index.html - self.register_server_fns(server_fn_route).route( - "/", - get(render_handler).with_state((cfg, SSRState::default())), - ) + self.connect_hot_reload() + .register_server_fns(server_fn_route) + .route( + "/", + get(render_handler).with_state((cfg, SSRState::default())), + ) + } + + fn connect_hot_reload(self) -> Self { + #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] + { + self.route( + "/_dioxus/hot_reload", + get(hot_reload_handler).with_state(crate::hot_reload::HotReloadState::default()), + ) + } + #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] + { + self + } } } @@ -195,3 +213,44 @@ fn report_err(e: E) -> Response { .body(body::boxed(format!("Error: {}", e))) .unwrap() } + +#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] +pub async fn hot_reload_handler( + ws: WebSocketUpgrade, + State(state): State, +) -> impl IntoResponse { + use axum::extract::ws::Message; + use futures_util::StreamExt; + + ws.on_upgrade(|mut socket| async move { + println!("🔥 Hot Reload WebSocket connected"); + { + // update any rsx calls that changed before the websocket connected. + { + println!("🔮 Finding updates since last compile..."); + let templates_read = state.templates.read().await; + + for template in &*templates_read { + if socket + .send(Message::Text(serde_json::to_string(&template).unwrap())) + .await + .is_err() + { + return; + } + } + } + println!("finished"); + } + + let mut rx = tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + while let Some(change) = rx.next().await { + if let Some(template) = change { + let template = { serde_json::to_string(&template).unwrap() }; + if socket.send(Message::Text(template)).await.is_err() { + break; + }; + } + } + }) +} diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index f3bbd5f43..24aab9643 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -17,6 +17,7 @@ use crate::{ pub trait DioxusRouterExt { fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn register_server_fns_with_handler( self, server_fn_route: &'static str, @@ -24,11 +25,14 @@ pub trait DioxusRouterExt { ) -> Self where H: Handler + 'static; + fn serve_dioxus_application( self, server_fn_path: &'static str, cfg: impl Into>, ) -> Self; + + fn connect_hot_reload(self) -> Self; } impl DioxusRouterExt for Router { @@ -92,9 +96,14 @@ impl DioxusRouterExt for Router { self = self.push(Router::with_path(route).get(serve_dir)) } - self.register_server_fns(server_fn_route) + self.connect_hot_reload() + .register_server_fns(server_fn_route) .push(Router::with_path("/").get(SSRHandler { cfg })) } + + fn connect_hot_reload(self) -> Self { + self.push(Router::with_path("/_dioxus/hot_reload").get(HotReloadHandler::default())) + } } struct SSRHandler { @@ -217,3 +226,79 @@ fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { resp_err.render(format!("Internal Server Error: {}", error)); *res = resp_err; } + +#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] +#[derive(Default)] +pub struct HotReloadHandler; + +#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] +#[handler] +impl HotReloadHandler { + async fn handle( + &self, + _req: &mut Request, + _depot: &mut Depot, + _res: &mut Response, + ) -> Result<(), salvo::http::StatusError> { + Err(salvo::http::StatusError::not_found()) + } +} + +#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] +#[derive(Default)] +pub struct HotReloadHandler { + state: crate::hot_reload::HotReloadState, +} + +#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] +#[handler] +impl HotReloadHandler { + async fn handle( + &self, + req: &mut Request, + _depot: &mut Depot, + res: &mut Response, + ) -> Result<(), salvo::http::StatusError> { + use salvo::ws::Message; + use salvo::ws::WebSocketUpgrade; + + let state = self.state.clone(); + + WebSocketUpgrade::new() + .upgrade(req, res, |mut websocket| async move { + use futures_util::StreamExt; + + println!("🔥 Hot Reload WebSocket connected"); + { + // update any rsx calls that changed before the websocket connected. + { + println!("🔮 Finding updates since last compile..."); + let templates_read = state.templates.read().await; + + for template in &*templates_read { + if websocket + .send(Message::text(serde_json::to_string(&template).unwrap())) + .await + .is_err() + { + return; + } + } + } + println!("finished"); + } + + let mut rx = + tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + while let Some(change) = rx.next().await { + if let Some(template) = change { + let template = { serde_json::to_string(&template).unwrap() }; + if websocket.send(Message::text(template)).await.is_err() { + break; + }; + } + } + }) + .await + } +} diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 82d1c382f..67c3c75e4 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -64,7 +64,8 @@ pub fn serve_dioxus_application( // Serve the dist folder and the index.html file let serve_dir = warp::fs::dir(cfg.assets_path); - register_server_fns(server_fn_route) + connect_hot_reload() + .or(register_server_fns(server_fn_route)) .or(warp::path::end() .and(warp::get()) .and(with_ssr_state()) @@ -159,3 +160,69 @@ fn report_err(e: E) -> Box { .unwrap(), ) as Box } + +pub fn connect_hot_reload() -> impl Filter { + #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] + { + warp::path("_dioxus/hot_reload").and(warp::ws()).map(|| { + Response::builder() + .status(StatusCode::NOT_FOUND) + .body("Not Found".into()) + .unwrap() + }) + } + #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] + { + use crate::hot_reload::HotReloadState; + let state = HotReloadState::default(); + + warp::path("_dioxus") + .and(warp::path("hot_reload")) + .and(warp::ws()) + .and(warp::any().map(move || state.clone())) + .map(move |ws: warp::ws::Ws, state: HotReloadState| { + #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] + ws.on_upgrade(move |mut websocket| { + async move { + use futures_util::sink::SinkExt; + use futures_util::StreamExt; + use warp::ws::Message; + + println!("🔥 Hot Reload WebSocket connected"); + { + // update any rsx calls that changed before the websocket connected. + { + println!("🔮 Finding updates since last compile..."); + let templates_read = state.templates.read().await; + + for template in &*templates_read { + if websocket + .send(Message::text( + serde_json::to_string(&template).unwrap(), + )) + .await + .is_err() + { + return; + } + } + } + println!("finished"); + } + + let mut rx = tokio_stream::wrappers::WatchStream::from_changes( + state.message_receiver, + ); + while let Some(change) = rx.next().await { + if let Some(template) = change { + let template = { serde_json::to_string(&template).unwrap() }; + if websocket.send(Message::text(template)).await.is_err() { + break; + }; + } + } + } + }) + }) + } +} diff --git a/packages/server/src/hot_reload.rs b/packages/server/src/hot_reload.rs new file mode 100644 index 000000000..c4f89e704 --- /dev/null +++ b/packages/server/src/hot_reload.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; + +use dioxus_core::Template; +use tokio::sync::{ + watch::{channel, Receiver}, + RwLock, +}; + +#[derive(Clone)] +pub struct HotReloadState { + // The cache of all templates that have been modified since the last time we checked + pub(crate) templates: Arc>>>, + // The channel to send messages to the hot reload thread + pub(crate) message_receiver: Receiver>>, +} + +impl Default for HotReloadState { + fn default() -> Self { + let templates = Arc::new(RwLock::new(std::collections::HashSet::new())); + let (tx, rx) = channel(None); + + dioxus_hot_reload::connect({ + let templates = templates.clone(); + move |msg| match msg { + dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { + { + let mut templates = templates.blocking_write(); + templates.insert(template); + } + + if let Err(err) = tx.send(Some(template)) { + log::error!("Failed to send hot reload message: {}", err); + } + } + dioxus_hot_reload::HotReloadMsg::Shutdown => { + std::process::exit(0); + } + } + }); + + Self { + templates, + message_receiver: rx, + } + } +} diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index a9c8e4939..5e395fa70 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -2,6 +2,8 @@ use dioxus_core::prelude::*; mod adapters; +#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] +mod hot_reload; #[cfg(feature = "ssr")] pub mod render; #[cfg(feature = "ssr")] diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index f6582d6a7..1f66067fd 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -9,36 +9,12 @@ use crate::prelude::ServeConfig; pub struct SSRState { // We keep a cache of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move renderers: Arc>, - #[cfg(all(debug_assertions, feature = "hot-reload"))] - // The cache of all templates that have been modified since the last time we checked - templates: Arc>>>, } impl Default for SSRState { fn default() -> Self { - #[cfg(all(debug_assertions, feature = "hot-reload"))] - let templates = { - let templates = Arc::new(std::sync::RwLock::new(std::collections::HashSet::new())); - dioxus_hot_reload::connect({ - let templates = templates.clone(); - move |msg| match msg { - dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { - if let Ok(mut templates) = templates.write() { - templates.insert(template); - } - } - dioxus_hot_reload::HotReloadMsg::Shutdown => { - std::process::exit(0); - } - } - }); - templates - }; - Self { renderers: Arc::new(object_pool::Pool::new(10, pre_renderer)), - #[cfg(all(debug_assertions, feature = "hot-reload"))] - templates, } } } From 987a0d5532c721675789334cec46994cdc0f5433 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 2 Apr 2023 18:13:27 -0500 Subject: [PATCH 385/895] fix salvo serving static files --- packages/server/src/adapters/salvo_adapter.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 24aab9643..357e1c19c 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -2,8 +2,9 @@ use std::{error::Error, sync::Arc}; use hyper::{http::HeaderValue, StatusCode}; use salvo::{ - async_trait, handler, serve_static::StaticDir, Depot, FlowCtrl, Handler, Request, Response, - Router, + async_trait, handler, + serve_static::{StaticDir, StaticFile}, + Depot, FlowCtrl, Handler, Request, Response, Router, }; use server_fn::{Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; @@ -80,7 +81,6 @@ impl DioxusRouterExt for Router { if path.ends_with("index.html") { continue; } - let serve_dir = StaticDir::new([path.clone()]); let route = path .strip_prefix(&cfg.assets_path) .unwrap() @@ -92,8 +92,15 @@ impl DioxusRouterExt for Router { }) .collect::>() .join("/"); - let route = format!("/{}/<**path>", route); - self = self.push(Router::with_path(route).get(serve_dir)) + if path.is_file() { + let route = format!("/{}", route); + let serve_dir = StaticFile::new(path.clone()); + self = self.push(Router::with_path(route).get(serve_dir)) + } else { + let route = format!("/{}/<**path>", route); + let serve_dir = StaticDir::new([path.clone()]); + self = self.push(Router::with_path(route).get(serve_dir)) + } } self.connect_hot_reload() From 3aa7349db76127774dd4bcc0ec0b896391b13d8b Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 3 Apr 2023 09:03:33 +0800 Subject: [PATCH 386/895] Add more features to todomvc (#928) - toggle-all button - double click modify todo item - filter state show mouse pointer - individual todo item remove button - correct active item count --- examples/todomvc.rs | 125 ++++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 39 deletions(-) diff --git a/examples/todomvc.rs b/examples/todomvc.rs index b5277133e..4b25507a5 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -7,7 +7,7 @@ fn main() { dioxus_desktop::launch(app); } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone, Copy)] pub enum FilterState { All, Active, @@ -39,56 +39,99 @@ pub fn app(cx: Scope<()>) -> Element { .collect::>(); filtered_todos.sort_unstable(); - let show_clear_completed = todos.values().any(|todo| todo.checked); - let items_left = filtered_todos.len(); - let item_text = match items_left { + let active_todo_count = todos.values().filter(|item| !item.checked).count(); + let active_todo_text = match active_todo_count { 1 => "item", _ => "items", }; - cx.render(rsx!{ + let show_clear_completed = todos.values().any(|todo| todo.checked); + + let selected = |state| { + if *filter == state { + "selected" + } else { + "false" + } + }; + + cx.render(rsx! { section { class: "todoapp", style { include_str!("./assets/todomvc.css") } - div { - 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() { - 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()); - } + 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() { + 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()); } } } + } + section { + class: "main", + if !todos.is_empty() { + rsx! { + input { + id: "toggle-all", + class: "toggle-all", + r#type: "checkbox", + onchange: move |_| { + let check = active_todo_count != 0; + for (_, item) in todos.make_mut().iter_mut() { + item.checked = check; + } + }, + checked: if active_todo_count == 0 { "true" } else { "false" }, + } + label { r#for: "toggle-all" } + } + } ul { class: "todo-list", - filtered_todos.iter().map(|id| rsx!(TodoEntry { key: "{id}", id: *id, todos: todos })) + filtered_todos.iter().map(|id| rsx!(TodoEntry { + key: "{id}", + id: *id, + todos: todos, + })) } (!todos.is_empty()).then(|| rsx!( footer { class: "footer", span { class: "todo-count", - strong {"{items_left} "} - span {"{item_text} left"} + strong {"{active_todo_count} "} + span {"{active_todo_text} left"} } ul { class: "filters", - li { class: "All", a { onclick: move |_| filter.set(FilterState::All), "All" }} - li { class: "Active", a { onclick: move |_| filter.set(FilterState::Active), "Active" }} - li { class: "Completed", a { onclick: move |_| filter.set(FilterState::Completed), "Completed" }} + for (state, state_text, url) in [ + (FilterState::All, "All", "#/"), + (FilterState::Active, "Active", "#/active"), + (FilterState::Completed, "Completed", "#/completed"), + ] { + li { + a { + href: url, + class: selected(state), + onclick: move |_| filter.set(state), + prevent_default: "onclick", + state_text + } + } + } } show_clear_completed.then(|| rsx!( button { @@ -102,8 +145,8 @@ pub fn app(cx: Scope<()>) -> Element { } } footer { class: "info", - p {"Double-click to edit a todo"} - p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }} + 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" }} } }) @@ -136,13 +179,17 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element { cx.props.todos.make_mut()[&cx.props.id].checked = evt.value.parse().unwrap(); } } - label { r#for: "cbg-{todo.id}", - onclick: move |_| is_editing.set(true), + ondblclick: 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", + } } is_editing.then(|| rsx!{ input { From d05c85db31d7e592bf91cc68589e2548b1767245 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 08:09:22 -0500 Subject: [PATCH 387/895] Document common items --- packages/server/src/adapters/mod.rs | 12 ++++ packages/server/src/lib.rs | 72 +++++++++++++++++-- packages/server/src/render.rs | 7 +- .../server/src/{serve.rs => serve_config.rs} | 7 +- packages/server/src/server_context.rs | 39 +++++++++- packages/server/src/server_fn.rs | 10 ++- 6 files changed, 132 insertions(+), 15 deletions(-) rename packages/server/src/{serve.rs => serve_config.rs} (85%) diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs index 0c292bd8d..148062db0 100644 --- a/packages/server/src/adapters/mod.rs +++ b/packages/server/src/adapters/mod.rs @@ -1,3 +1,15 @@ +//! # Adapters +//! Adapters for different web frameworks. +//! +//! Each adapter provides a set of utilities that is ergonomic to use with the framework. +//! +//! Each framework has utilies for some or all of the following: +//! - Server functions +//! - A generic way to register server functions +//! - A way to register server functions with a custom handler that allows users to pass in a custom [`DioxusServerContext`] based on the state of the server framework. +//! - A way to register static WASM files that is accepts [`ServeConfig`] +//! - A hot reloading web socket that intigrates with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload) + #[cfg(feature = "axum")] pub mod axum_adapter; #[cfg(feature = "salvo")] diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 5e395fa70..9654adebe 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -1,3 +1,66 @@ +//! Fullstack utilities for the [`dioxus`](https://dioxuslabs.com) framework. +//! +//! # Features +//! - Intigrations with the [axum](crate::adapters::axum_adapter), [salvo](crate::adapters::salvo_adapters), and [warp](crate::adapters::warp_adapters) server frameworks with utilities for serving and rendering Dioxus applications. +//! - Server functions that allow you to call code on the server from the client as if it were a normal function. +//! - Instant RSX Hot reloading with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload). +//! +//! # Example +//! ```rust +//! #![allow(non_snake_case)] +//! use dioxus::prelude::*; +//! use dioxus_server::prelude::*; +//! +//! fn main() { +//! #[cfg(feature = "web")] +//! // Hydrate the application on the client +//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); +//! #[cfg(feature = "ssr")] +//! { +//! GetServerData::register().unwrap(); +//! tokio::runtime::Runtime::new() +//! .unwrap() +//! .block_on(async move { +//! let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); +//! axum::Server::bind(&addr) +//! .serve( +//! axum::Router::new() +//! // Server side render the application, serve static assets, and register server functions +//! .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) +//! .into_make_service(), +//! ) +//! .await +//! .unwrap(); +//! }); +//! } +//! } +//! +//! fn app(cx: Scope) -> Element { +//! let text = use_state(cx, || "...".to_string()); +//! +//! cx.render(rsx! { +//! button { +//! onclick: move |_| { +//! to_owned![text]; +//! async move { +//! if let Ok(data) = get_server_data().await { +//! text.set(data.clone()); +//! } +//! } +//! }, +//! "Run a server function" +//! } +//! "Server said: {text}" +//! }) +//! } +//! +//! #[server(GetServerData)] +//! async fn get_server_data() -> Result { +//! Ok("Hello from the server!".to_string()) +//! } +//! ``` + +#![warn(missing_docs)] #[allow(unused)] use dioxus_core::prelude::*; @@ -5,12 +68,13 @@ mod adapters; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] mod hot_reload; #[cfg(feature = "ssr")] -pub mod render; +mod render; #[cfg(feature = "ssr")] -mod serve; +mod serve_config; mod server_context; mod server_fn; +/// A prelude of commonly used items in dioxus-server. pub mod prelude { #[cfg(feature = "axum")] pub use crate::adapters::axum_adapter::*; @@ -19,9 +83,7 @@ pub mod prelude { #[cfg(feature = "warp")] pub use crate::adapters::warp_adapter::*; #[cfg(feature = "ssr")] - pub use crate::render::*; - #[cfg(feature = "ssr")] - pub use crate::serve::{ServeConfig, ServeConfigBuilder}; + pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; pub use crate::server_context::DioxusServerContext; pub use crate::server_fn::ServerFn; #[cfg(feature = "ssr")] diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 1f66067fd..22e751ea8 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -1,3 +1,5 @@ +//! A shared pool of renderers for efficient server side rendering. + use std::sync::Arc; use dioxus_core::VirtualDom; @@ -5,9 +7,10 @@ use dioxus_ssr::Renderer; use crate::prelude::ServeConfig; +/// State used in server side rendering. This utilizes a pool of [`dioxus_ssr::Renderer`]s to cache static templates between renders. #[derive(Clone)] -pub struct SSRState { - // We keep a cache of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move +pub(crate) struct SSRState { + // We keep a pool of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move renderers: Arc>, } diff --git a/packages/server/src/serve.rs b/packages/server/src/serve_config.rs similarity index 85% rename from packages/server/src/serve.rs rename to packages/server/src/serve_config.rs index 6284a6f1b..b7b29e9fb 100644 --- a/packages/server/src/serve.rs +++ b/packages/server/src/serve_config.rs @@ -1,9 +1,12 @@ +//! Configeration for how to serve a Dioxus application + use std::fs::File; use std::io::Read; use std::path::PathBuf; use dioxus_core::Component; +/// A ServeConfig is used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`]. #[derive(Clone)] pub struct ServeConfigBuilder { pub(crate) app: Component

, @@ -14,7 +17,7 @@ pub struct ServeConfigBuilder { } impl ServeConfigBuilder

{ - /// Create a new ServeConfig + /// Create a new ServeConfigBuilder with the root component and props to render on the server. pub fn new(app: Component

, props: P) -> Self { Self { app, @@ -95,6 +98,8 @@ pub(crate) struct IndexHtml { pub(crate) post_main: String, } +/// Used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`]. +/// See [`ServeConfigBuilder`] to create a ServeConfig #[derive(Clone)] pub struct ServeConfig { pub(crate) app: Component

, diff --git a/packages/server/src/server_context.rs b/packages/server/src/server_context.rs index 427ee21f8..7e2a494c5 100644 --- a/packages/server/src/server_context.rs +++ b/packages/server/src/server_context.rs @@ -4,7 +4,8 @@ use anymap::{any::Any, Map}; type SendSyncAnyMap = Map; -/// A shared context for server functions. This allows you to pass data between your server and the server functions like authentication session data. +/// A shared context for server functions. +/// This allows you to pass data between your server framework and the server functions. This can be used to pass request information or information about the state of the server. For example, you could pass authentication data though this context to your server functions. #[derive(Clone)] pub struct DioxusServerContext { shared_context: Arc>, @@ -19,10 +20,12 @@ impl Default for DioxusServerContext { } impl DioxusServerContext { + /// Clone a value from the shared server context pub fn get(&self) -> Option { self.shared_context.read().ok()?.get::().cloned() } + /// Insert a value into the shared server context pub fn insert( &mut self, value: T, @@ -33,3 +36,37 @@ impl DioxusServerContext { .map(|_| ()) } } + +/// Generate a server context from a tuple of values +macro_rules! server_context { + ($({$(($name:ident: $ty:ident)),*}),*) => { + $( + #[allow(unused_mut)] + impl< $($ty: Send + Sync + 'static),* > From<($($ty,)*)> for $crate::server_context::DioxusServerContext { + fn from(( $($name,)* ): ($($ty,)*)) -> Self { + let mut context = $crate::server_context::DioxusServerContext::default(); + $(context.insert::<$ty>($name).unwrap();)* + context + } + } + )* + }; +} + +server_context!( + {}, + {(a: A)}, + {(a: A), (b: B)}, + {(a: A), (b: B), (c: C)}, + {(a: A), (b: B), (c: C), (d: D)}, + {(a: A), (b: B), (c: C), (d: D), (e: E)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L), (m: M)}, + {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L), (m: M), (n: N)} +); diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs index 7170d61de..6f985a39a 100644 --- a/packages/server/src/server_fn.rs +++ b/packages/server/src/server_fn.rs @@ -1,6 +1,7 @@ use crate::server_context::DioxusServerContext; #[cfg(any(feature = "ssr", doc))] +/// A trait object for a function that be called on serializable arguments and returns a serializable result. pub type ServerFnTraitObj = server_fn::ServerFnTraitObj; #[cfg(any(feature = "ssr", doc))] @@ -78,17 +79,14 @@ pub enum ServerRegistrationFnError { /// Defines a "server function." A server function can be called from the server or the client, /// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. /// -/// (This follows the same convention as the Dioxus framework's distinction between `ssr` for server-side rendering, -/// and `csr` and `hydrate` for client-side rendering and hydration, respectively.) -/// /// Server functions are created using the `server` macro. /// /// The function should be registered by calling `ServerFn::register()`. The set of server functions -/// can be queried on the server for routing purposes by calling [server_fn_by_path]. +/// can be queried on the server for routing purposes by calling [ServerFunctionRegistry::get]. /// -/// Technically, the trait is implemented on a type that describes the server function's arguments. +/// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. pub trait ServerFn: server_fn::ServerFn { - /// Registers the server function, allowing the server to query it by URL. + /// Registers the server function, allowing the client to query it by URL. #[cfg(any(feature = "ssr", doc))] fn register() -> Result<(), server_fn::ServerFnError> { Self::register_in::() From 9d5d64737803a4b2e31e55a13fe10e1204bf594d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 08:09:30 -0500 Subject: [PATCH 388/895] document axum adapter --- packages/server/src/adapters/axum_adapter.rs | 179 ++++++++++++++++++- 1 file changed, 175 insertions(+), 4 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 9fbcd5893..ad3fafd6a 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -1,3 +1,60 @@ +//! Dioxus utilities for the [Axum](https://docs.rs/axum/latest/axum/index.html) server framework. +//! +//! # Example +//! ```rust +//! # #![allow(non_snake_case)] +//! # use dioxus::prelude::*; +//! # use dioxus_server::prelude::*; +//! +//! fn main() { +//! #[cfg(feature = "web")] +//! // Hydrate the application on the client +//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); +//! #[cfg(feature = "ssr")] +//! { +//! GetServerData::register().unwrap(); +//! tokio::runtime::Runtime::new() +//! .unwrap() +//! .block_on(async move { +//! let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); +//! axum::Server::bind(&addr) +//! .serve( +//! axum::Router::new() +//! // Server side render the application, serve static assets, and register server functions +//! .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) +//! .into_make_service(), +//! ) +//! .await +//! .unwrap(); +//! }); +//! } +//! } +//! +//! fn app(cx: Scope) -> Element { +//! let text = use_state(cx, || "...".to_string()); +//! +//! cx.render(rsx! { +//! button { +//! onclick: move |_| { +//! to_owned![text]; +//! async move { +//! if let Ok(data) = get_server_data().await { +//! text.set(data.clone()); +//! } +//! } +//! }, +//! "Run a server function" +//! } +//! "Server said: {text}" +//! }) +//! } +//! +//! #[server(GetServerData)] +//! async fn get_server_data() -> Result { +//! Ok("Hello from the server!".to_string()) +//! } +//! ``` + use std::{error::Error, sync::Arc}; use axum::{ @@ -14,12 +71,41 @@ use tokio::task::spawn_blocking; use crate::{ render::SSRState, - serve::ServeConfig, + serve_config::ServeConfig, server_context::DioxusServerContext, server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; +/// A extension trait with utilities for integrating Dioxus with your Axum router. pub trait DioxusRouterExt { + /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. + /// + /// # Example + /// ```rust + /// # use dioxus::prelude::*; + /// # use dioxus_server::prelude::*; + /// + /// fn main() { + /// tokio::runtime::Runtime::new() + /// .unwrap() + /// .block_on(async move { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns_with_handler("", |func| { + /// move |headers: HeaderMap, body: Request| async move { + /// // Add the headers to the context + /// server_fn_handler((headers.clone(),).into(), func.clone(), headers, body).await + /// } + /// }) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); + /// }); + /// } + /// ``` fn register_server_fns_with_handler( self, server_fn_route: &'static str, @@ -29,15 +115,98 @@ pub trait DioxusRouterExt { H: Handler, T: 'static, S: Clone + Send + Sync + 'static; + + /// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. + /// + /// # Example + /// ```rust + /// # use dioxus::prelude::*; + /// # use dioxus_server::prelude::*; + /// + /// fn main() { + /// tokio::runtime::Runtime::new() + /// .unwrap() + /// .block_on(async move { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns("") + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); + /// }); + /// } + /// ``` fn register_server_fns(self, server_fn_route: &'static str) -> Self; + /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. + /// + /// # Example + /// /// # Example + /// ```rust + /// # #![allow(non_snake_case)] + /// # use dioxus::prelude::*; + /// # use dioxus_server::prelude::*; + /// + /// fn main() { + /// GetServerData::register().unwrap(); + /// tokio::runtime::Runtime::new() + /// .unwrap() + /// .block_on(async move { + /// hot_reload_init!(); + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .connect_hot_reload() + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); + /// }); + /// } + /// + /// # fn app(cx: Scope) -> Element {todo!()} + /// ``` + fn connect_hot_reload(self) -> Self; + + /// Serves the Dioxus application. This will serve a complete server side rendered application. + /// It will serve static assets, server render the application, register server functions, and intigrate with hot reloading. + /// + /// # Example + /// ```rust + /// # #![allow(non_snake_case)] + /// # use dioxus::prelude::*; + /// # use dioxus_server::prelude::*; + /// + /// fn main() { + /// GetServerData::register().unwrap(); + /// tokio::runtime::Runtime::new() + /// .unwrap() + /// .block_on(async move { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); + /// }); + /// } + /// + /// # fn app(cx: Scope) -> Element {todo!()} + /// ``` fn serve_dioxus_application( self, server_fn_route: &'static str, cfg: impl Into>, ) -> Self; - - fn connect_hot_reload(self) -> Self; } impl DioxusRouterExt for Router @@ -66,7 +235,7 @@ where fn register_server_fns(self, server_fn_route: &'static str) -> Self { self.register_server_fns_with_handler(server_fn_route, |func| { move |headers: HeaderMap, body: Request| async move { - server_fn_handler(DioxusServerContext::default(), func.clone(), headers, body).await + server_fn_handler(().into(), func.clone(), headers, body).await } }) } @@ -143,6 +312,7 @@ async fn render_handler( Full::from(rendered) } +/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub async fn server_fn_handler( server_context: DioxusServerContext, function: Arc, @@ -214,6 +384,7 @@ fn report_err(e: E) -> Response { .unwrap() } +/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] pub async fn hot_reload_handler( ws: WebSocketUpgrade, From 556e4f374b1cf226e4302e4150a381990118a512 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 11:59:40 -0500 Subject: [PATCH 389/895] Document salvo adapter --- packages/server/src/adapters/axum_adapter.rs | 127 ++++++------- packages/server/src/adapters/salvo_adapter.rs | 167 +++++++++++++++++- 2 files changed, 217 insertions(+), 77 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index ad3fafd6a..34e6a5e46 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -39,7 +39,7 @@ //! to_owned![text]; //! async move { //! if let Ok(data) = get_server_data().await { -//! text.set(data.clone()); +//! text.set(data); //! } //! } //! }, @@ -85,25 +85,22 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// .register_server_fns_with_handler("", |func| { - /// move |headers: HeaderMap, body: Request| async move { - /// // Add the headers to the context - /// server_fn_handler((headers.clone(),).into(), func.clone(), headers, body).await - /// } - /// }) - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns_with_handler("", |func| { + /// move |headers: HeaderMap, body: Request| async move { + /// // Add the headers to the context + /// server_fn_handler((headers.clone(),), func.clone(), headers, body).await + /// } + /// }) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// ``` fn register_server_fns_with_handler( @@ -123,20 +120,17 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// .register_server_fns("") - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// .register_server_fns("") + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// ``` fn register_server_fns(self, server_fn_route: &'static str) -> Self; @@ -150,23 +144,19 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// GetServerData::register().unwrap(); - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// hot_reload_init!(); - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// // Server side render the application, serve static assets, and register server functions - /// .connect_hot_reload() - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// hot_reload_init!(); + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .connect_hot_reload() + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// /// # fn app(cx: Scope) -> Element {todo!()} @@ -174,7 +164,7 @@ pub trait DioxusRouterExt { fn connect_hot_reload(self) -> Self; /// Serves the Dioxus application. This will serve a complete server side rendered application. - /// It will serve static assets, server render the application, register server functions, and intigrate with hot reloading. + /// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. /// /// # Example /// ```rust @@ -182,22 +172,18 @@ pub trait DioxusRouterExt { /// # use dioxus::prelude::*; /// # use dioxus_server::prelude::*; /// - /// fn main() { - /// GetServerData::register().unwrap(); - /// tokio::runtime::Runtime::new() - /// .unwrap() - /// .block_on(async move { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// // Server side render the application, serve static assets, and register server functions - /// .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// }); + /// #[tokio::main] + /// async fn main() { + /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + /// axum::Server::bind(&addr) + /// .serve( + /// axum::Router::new() + /// // Server side render the application, serve static assets, and register server functions + /// .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + /// .into_make_service(), + /// ) + /// .await + /// .unwrap(); /// } /// /// # fn app(cx: Scope) -> Element {todo!()} @@ -235,7 +221,7 @@ where fn register_server_fns(self, server_fn_route: &'static str) -> Self { self.register_server_fns_with_handler(server_fn_route, |func| { move |headers: HeaderMap, body: Request| async move { - server_fn_handler(().into(), func.clone(), headers, body).await + server_fn_handler((), func.clone(), headers, body).await } }) } @@ -314,11 +300,12 @@ async fn render_handler( /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub async fn server_fn_handler( - server_context: DioxusServerContext, + server_context: impl Into, function: Arc, headers: HeaderMap, req: Request, ) -> impl IntoResponse { + let server_context = server_context.into(); let (_, body) = req.into_parts(); let body = hyper::body::to_bytes(body).await; let Ok(body)=body else { diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 357e1c19c..6bc8947a6 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -1,3 +1,54 @@ +//! Dioxus utilities for the [Salvo](https://salvo.rs) server framework. +//! +//! # Example +//! ```rust +//! # #![allow(non_snake_case)] +//! # use dioxus::prelude::*; +//! # use dioxus_server::prelude::*; +//! +//! fn main() { +//! #[cfg(feature = "web")] +//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); +//! #[cfg(feature = "ssr")] +//! { +//! use salvo::prelude::*; +//! GetServerData::register().unwrap(); +//! tokio::runtime::Runtime::new() +//! .unwrap() +//! .block_on(async move { +//! let router = +//! Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); +//! Server::new(TcpListener::bind("127.0.0.1:8080")) +//! .serve(router) +//! .await; +//! }); +//! } +//! } +//! +//! fn app(cx: Scope) -> Element { +//! let text = use_state(cx, || "...".to_string()); +//! +//! cx.render(rsx! { +//! button { +//! onclick: move |_| { +//! to_owned![text]; +//! async move { +//! if let Ok(data) = get_server_data().await { +//! text.set(data); +//! } +//! } +//! }, +//! "Run a server function" +//! } +//! "Server said: {text}" +//! }) +//! } +//! +//! #[server(GetServerData)] +//! async fn get_server_data() -> Result { +//! Ok("Hello from the server!".to_string()) +//! } + use std::{error::Error, sync::Arc}; use hyper::{http::HeaderValue, StatusCode}; @@ -11,14 +62,51 @@ use tokio::task::spawn_blocking; use crate::{ prelude::DioxusServerContext, - prelude::SSRState, - serve::ServeConfig, + render::SSRState, + serve_config::ServeConfig, server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; +/// A extension trait with utilities for integrating Dioxus with your Salvo router. pub trait DioxusRouterExt { - fn register_server_fns(self, server_fn_route: &'static str) -> Self; - + /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. + /// + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// struct ServerFunctionHandler { + /// server_fn: Arc, + /// } + /// + /// #[handler] + /// impl ServerFunctionHandler { + /// async fn handle( + /// &self, + /// req: &mut Request, + /// depot: &mut Depot, + /// res: &mut Response, + /// flow: &mut FlowCtrl, + /// ) { + /// // Add the headers to server context + /// ServerFnHandler::new((req.headers().clone(),), self.server_fn.clone()) + /// .handle(req, depot, res, flow) + /// .await + /// } + /// } + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .register_server_fns_with_handler("", |func| { + /// ServerFnHandler::new(DioxusServerContext::default(), func) + /// }); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// ``` fn register_server_fns_with_handler( self, server_fn_route: &'static str, @@ -27,13 +115,70 @@ pub trait DioxusRouterExt { where H: Handler + 'static; + /// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. + /// + /// # Example + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .register_server_fns(""); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// + /// ``` + fn register_server_fns(self, server_fn_route: &'static str) -> Self; + + /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. + /// + /// # Example + /// ```rust + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// use dioxus_server::prelude::*; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new() + /// .connect_hot_reload(); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + fn connect_hot_reload(self) -> Self; + + /// Serves the Dioxus application. This will serve a complete server side rendered application. + /// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. + /// + /// # Example + /// ```rust + /// #![allow(non_snake_case)] + /// use dioxus::prelude::*; + /// use dioxus_server::prelude::*; + /// use salvo::prelude::*; + /// use std::{net::TcpListener, sync::Arc}; + /// + /// #[tokio::main] + /// async fn main() { + /// let router = Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); + /// Server::new(TcpListener::bind("127.0.0.1:8080")) + /// .serve(router) + /// .await; + /// } + /// + /// # fn app(cx: Scope) -> Element {todo!()} + /// ``` fn serve_dioxus_application( self, server_fn_path: &'static str, cfg: impl Into>, ) -> Self; - - fn connect_hot_reload(self) -> Self; } impl DioxusRouterExt for Router { @@ -138,13 +283,19 @@ impl Handler for SSRHandler

{ } } +/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub struct ServerFnHandler { server_context: DioxusServerContext, function: Arc, } impl ServerFnHandler { - pub fn new(server_context: DioxusServerContext, function: Arc) -> Self { + /// Create a new server function handler with the given server context and server function. + pub fn new( + server_context: impl Into, + function: Arc, + ) -> Self { + let server_context = server_context.into(); Self { server_context, function, @@ -234,6 +385,7 @@ fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { *res = resp_err; } +/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] #[derive(Default)] pub struct HotReloadHandler; @@ -251,6 +403,7 @@ impl HotReloadHandler { } } +/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[derive(Default)] pub struct HotReloadHandler { From b8ca41bd92019b293d902195759e712a121b91cd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 12:15:59 -0500 Subject: [PATCH 390/895] document warp adapter --- packages/server/src/adapters/axum_adapter.rs | 30 ++-- packages/server/src/adapters/salvo_adapter.rs | 10 +- packages/server/src/adapters/warp_adapter.rs | 131 +++++++++++++++++- 3 files changed, 145 insertions(+), 26 deletions(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 34e6a5e46..c9bf9ba77 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -2,9 +2,9 @@ //! //! # Example //! ```rust -//! # #![allow(non_snake_case)] -//! # use dioxus::prelude::*; -//! # use dioxus_server::prelude::*; +//! #![allow(non_snake_case)] +//! use dioxus::prelude::*; +//! use dioxus_server::prelude::*; //! //! fn main() { //! #[cfg(feature = "web")] @@ -82,8 +82,8 @@ pub trait DioxusRouterExt { /// /// # Example /// ```rust - /// # use dioxus::prelude::*; - /// # use dioxus_server::prelude::*; + /// use dioxus::prelude::*; + /// use dioxus_server::prelude::*; /// /// #[tokio::main] /// async fn main() { @@ -117,8 +117,8 @@ pub trait DioxusRouterExt { /// /// # Example /// ```rust - /// # use dioxus::prelude::*; - /// # use dioxus_server::prelude::*; + /// use dioxus::prelude::*; + /// use dioxus_server::prelude::*; /// /// #[tokio::main] /// async fn main() { @@ -138,11 +138,9 @@ pub trait DioxusRouterExt { /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. /// /// # Example - /// /// # Example /// ```rust - /// # #![allow(non_snake_case)] - /// # use dioxus::prelude::*; - /// # use dioxus_server::prelude::*; + /// #![allow(non_snake_case)] + /// use dioxus_server::prelude::*; /// /// #[tokio::main] /// async fn main() { @@ -158,8 +156,6 @@ pub trait DioxusRouterExt { /// .await /// .unwrap(); /// } - /// - /// # fn app(cx: Scope) -> Element {todo!()} /// ``` fn connect_hot_reload(self) -> Self; @@ -168,9 +164,9 @@ pub trait DioxusRouterExt { /// /// # Example /// ```rust - /// # #![allow(non_snake_case)] - /// # use dioxus::prelude::*; - /// # use dioxus_server::prelude::*; + /// #![allow(non_snake_case)] + /// use dioxus::prelude::*; + /// use dioxus_server::prelude::*; /// /// #[tokio::main] /// async fn main() { @@ -186,7 +182,7 @@ pub trait DioxusRouterExt { /// .unwrap(); /// } /// - /// # fn app(cx: Scope) -> Element {todo!()} + /// fn app(cx: Scope) -> Element {todo!()} /// ``` fn serve_dioxus_application( self, diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 6bc8947a6..ffe72bef5 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -2,9 +2,9 @@ //! //! # Example //! ```rust -//! # #![allow(non_snake_case)] -//! # use dioxus::prelude::*; -//! # use dioxus_server::prelude::*; +//! #![allow(non_snake_case)] +//! use dioxus::prelude::*; +//! use dioxus_server::prelude::*; //! //! fn main() { //! #[cfg(feature = "web")] @@ -48,6 +48,7 @@ //! async fn get_server_data() -> Result { //! Ok("Hello from the server!".to_string()) //! } +//! ``` use std::{error::Error, sync::Arc}; @@ -71,6 +72,7 @@ use crate::{ pub trait DioxusRouterExt { /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. /// + /// # Example /// ```rust /// use salvo::prelude::*; /// use std::{net::TcpListener, sync::Arc}; @@ -172,7 +174,7 @@ pub trait DioxusRouterExt { /// .await; /// } /// - /// # fn app(cx: Scope) -> Element {todo!()} + /// fn app(cx: Scope) -> Element {todo!()} /// ``` fn serve_dioxus_application( self, diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 67c3c75e4..5041e294d 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -1,3 +1,52 @@ +//! Dioxus utilities for the [Warp](https://docs.rs/warp/latest/warp/index.html) server framework. +//! +//! # Example +//! ```rust +//! #![allow(non_snake_case)] +//! use dioxus::prelude::*; +//! use dioxus_server::prelude::*; +//! +//! fn main() { +//! #[cfg(feature = "web")] +//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); +//! #[cfg(feature = "ssr")] +//! { +//! GetServerData::register().unwrap(); +//! tokio::runtime::Runtime::new() +//! .unwrap() +//! .block_on(async move { +//! let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ())); +//! warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +//! }); +//! } +//! } +//! +//! fn app(cx: Scope) -> Element { +//! let text = use_state(cx, || "...".to_string()); +//! +//! cx.render(rsx! { +//! button { +//! onclick: move |_| { +//! to_owned![text]; +//! async move { +//! if let Ok(data) = get_server_data().await { +//! text.set(data); +//! } +//! } +//! }, +//! "Run a server function" +//! } +//! "Server said: {text}" +//! }) +//! } +//! +//! #[server(GetServerData)] +//! async fn get_server_data() -> Result { +//! Ok("Hello from the server!".to_string()) +//! } +//! +//! ``` + use std::{error::Error, sync::Arc}; use server_fn::{Payload, ServerFunctionRegistry}; @@ -10,11 +59,36 @@ use warp::{ }; use crate::{ - prelude::{DioxusServerContext, SSRState}, - serve::ServeConfig, + prelude::DioxusServerContext, + render::SSRState, + serve_config::ServeConfig, server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, }; +/// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. +/// +/// # Example +/// ```rust +/// use warp::{body, header, hyper::HeaderMap, path, post, Filter}; +/// +/// #[tokio::main] +/// async fn main() { +/// let routes = register_server_fns_with_handler("", |full_route, func| { +/// path(full_route) +/// .and(post()) +/// .and(header::headers_cloned()) +/// .and(body::bytes()) +/// .and_then(move |headers: HeaderMap, body| { +/// let func = func.clone(); +/// async move { +/// // Add the headers to the server function context +/// server_fn_handler((headers.clone(),), func, headers, body).await +/// } +/// }) +/// }); +/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +/// } +/// ``` pub fn register_server_fns_with_handler( server_fn_route: &'static str, mut handler: H, @@ -41,6 +115,18 @@ where filter.expect("No server functions found") } +/// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. +/// +/// # Example +/// ```rust +/// use dioxus_server::prelude::*; +/// +/// #[tokio::main] +/// async fn main() { +/// let routes = register_server_fns(""); +/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +/// } +/// ``` pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { register_server_fns_with_handler(server_fn_route, |full_route, func| { path(full_route) @@ -56,6 +142,25 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R }) } +/// Serves the Dioxus application. This will serve a complete server side rendered application. +/// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. +/// +/// # Example +/// ```rust +/// #![allow(non_snake_case)] +/// use dioxus::prelude::*; +/// use dioxus_server::prelude::*; +/// +/// #[tokio::main] +/// async fn main() { +/// let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ())); +/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +/// } +/// +/// fn app(cx: Scope) -> Element { +/// todo!() +/// } +/// ``` pub fn serve_dioxus_application( server_fn_route: &'static str, cfg: impl Into>, @@ -90,12 +195,14 @@ struct RecieveFailed(String); impl warp::reject::Reject for RecieveFailed {} -async fn server_fn_handler( - server_context: DioxusServerContext, +/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. +pub async fn server_fn_handler( + server_context: impl Into, function: Arc, headers: HeaderMap, body: Bytes, ) -> Result, warp::Rejection> { + let server_context = server_context.into(); // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); spawn_blocking({ @@ -161,7 +268,21 @@ fn report_err(e: E) -> Box { ) as Box } -pub fn connect_hot_reload() -> impl Filter { +/// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. +/// +/// # Example +/// ```rust +/// #![allow(non_snake_case)] +/// use dioxus_server::prelude::*; +/// +/// #[tokio::main] +/// async fn main() { +/// let routes = connect_hot_reload(); +/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +/// } +/// ``` +pub fn connect_hot_reload() -> impl Filter + Clone +{ #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] { warp::path("_dioxus/hot_reload").and(warp::ws()).map(|| { From 10a1c46a49458db192410118394ee74e741c73e0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 12:45:01 -0500 Subject: [PATCH 391/895] make server crate example more compelling --- packages/server/src/lib.rs | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 9654adebe..7ef232c23 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -6,6 +6,7 @@ //! - Instant RSX Hot reloading with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload). //! //! # Example +//! Full stack Dioxus in under 50 lines of code //! ```rust //! #![allow(non_snake_case)] //! use dioxus::prelude::*; @@ -13,50 +14,45 @@ //! //! fn main() { //! #[cfg(feature = "web")] -//! // Hydrate the application on the client //! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); //! #[cfg(feature = "ssr")] //! { -//! GetServerData::register().unwrap(); +//! GetMeaning::register().unwrap(); //! tokio::runtime::Runtime::new() //! .unwrap() //! .block_on(async move { -//! let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); -//! axum::Server::bind(&addr) -//! .serve( -//! axum::Router::new() -//! // Server side render the application, serve static assets, and register server functions -//! .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) -//! .into_make_service(), -//! ) -//! .await -//! .unwrap(); +//! warp::serve(serve_dioxus_application( +//! "", +//! ServeConfigBuilder::new(app, ()), +//! )) +//! .run(([127, 0, 0, 1], 8080)) +//! .await; //! }); -//! } +//! } //! } //! //! fn app(cx: Scope) -> Element { -//! let text = use_state(cx, || "...".to_string()); -//! +//! let meaning = use_state(cx, || None); //! cx.render(rsx! { //! button { //! onclick: move |_| { -//! to_owned![text]; +//! to_owned![meaning]; //! async move { -//! if let Ok(data) = get_server_data().await { -//! text.set(data.clone()); +//! if let Ok(data) = get_meaning("life the universe and everything".into()).await { +//! meaning.set(data); //! } //! } //! }, //! "Run a server function" //! } -//! "Server said: {text}" +//! "Server said: {meaning:?}" //! }) //! } //! -//! #[server(GetServerData)] -//! async fn get_server_data() -> Result { -//! Ok("Hello from the server!".to_string()) +//! // This code will only run on the server +//! #[server(GetMeaning)] +//! async fn get_meaning(of: String) -> Result, ServerFnError> { +//! Ok(of.contains("life").then(|| 42)) //! } //! ``` From 830dd6fa9737f6ead349093f3a492828ab341a4f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 13:09:25 -0500 Subject: [PATCH 392/895] use git version of server functions --- packages/server/Cargo.toml | 2 +- packages/server/server-macro/Cargo.toml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 563912754..fddeccbde 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] # server functions -server_fn = { path = "D:/Users/Desktop/github/leptos/server_fn", features = ["stable"] } +server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "a9e6590b5e7f1c0b01da7db7b86719cb18a4aaa1", features = ["stable"] } server_macro = { path = "server-macro" } # warp diff --git a/packages/server/server-macro/Cargo.toml b/packages/server/server-macro/Cargo.toml index e5fb6523e..d03c5274c 100644 --- a/packages/server/server-macro/Cargo.toml +++ b/packages/server/server-macro/Cargo.toml @@ -7,8 +7,7 @@ edition = "2021" [dependencies] quote = "1.0.26" -# server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "1e037ecb60965c7c55fd781fdc8de7863ffd102b", features = ["stable"] } -server_fn_macro = { path = "D:/Users/Desktop/github/leptos/server_fn_macro", features = ["stable"] } +server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "a9e6590b5e7f1c0b01da7db7b86719cb18a4aaa1", features = ["stable"] } syn = { version = "1", features = ["full"] } [lib] From f1c31d6cc368607c1310452b2554b4e06c936e2d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 13:09:34 -0500 Subject: [PATCH 393/895] mark examples as don't publish --- packages/server/examples/axum-hello-world/Cargo.toml | 1 + packages/server/examples/axum-router/Cargo.toml | 1 + packages/server/examples/salvo-hello-world/Cargo.toml | 1 + packages/server/examples/warp-hello-world/Cargo.toml | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index ed466e6e1..50d5e05b3 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -2,6 +2,7 @@ name = "axum-hello-world" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml index 297aa6726..699779763 100644 --- a/packages/server/examples/axum-router/Cargo.toml +++ b/packages/server/examples/axum-router/Cargo.toml @@ -2,6 +2,7 @@ name = "axum-router" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 4633eaafc..1ddf52915 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -2,6 +2,7 @@ name = "salvo-hello-world" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index 86ac2da5b..cbd8606dd 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -2,6 +2,7 @@ name = "warp-hello-world" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 7ae45272d1e7ee642501d574ecb32f9a7b6d9345 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 13:20:38 -0500 Subject: [PATCH 394/895] fix some doc links in dioxus-server --- packages/server/server-macro/src/lib.rs | 6 +++--- packages/server/src/adapters/axum_adapter.rs | 4 +++- packages/server/src/adapters/mod.rs | 4 ++-- packages/server/src/lib.rs | 6 ++++-- packages/server/src/server_fn.rs | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/server/server-macro/src/lib.rs b/packages/server/server-macro/src/lib.rs index f6b4f92a2..e34a440d4 100644 --- a/packages/server/server-macro/src/lib.rs +++ b/packages/server/server-macro/src/lib.rs @@ -19,7 +19,7 @@ use server_fn_macro::*; /// work without WebAssembly, the encoding must be `"Url"`. /// /// The server function itself can take any number of arguments, each of which should be serializable -/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](dioxus_server::prelude::DioxusServerContext), +/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html), /// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other /// server-side context into the server function. /// @@ -50,8 +50,8 @@ use server_fn_macro::*; /// They are serialized as an `application/x-www-form-urlencoded` /// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor` /// using [`cbor`](https://docs.rs/cbor/latest/cbor/). -/// - **The [DioxusServerContext](dioxus_server::prelude::DioxusServerContext) comes from the server.** Optionally, the first argument of a server function -/// can be a [DioxusServerContext](dioxus_server::prelude::DioxusServerContext). This scope can be used to inject dependencies like the HTTP request +/// - **The [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html) comes from the server.** Optionally, the first argument of a server function +/// can be a [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html). This scope can be used to inject dependencies like the HTTP request /// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client. #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index c9bf9ba77..f4bdd8a96 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -182,7 +182,9 @@ pub trait DioxusRouterExt { /// .unwrap(); /// } /// - /// fn app(cx: Scope) -> Element {todo!()} + /// fn app(cx: Scope) -> Element { + /// todo!() + /// } /// ``` fn serve_dioxus_application( self, diff --git a/packages/server/src/adapters/mod.rs b/packages/server/src/adapters/mod.rs index 148062db0..5809132b8 100644 --- a/packages/server/src/adapters/mod.rs +++ b/packages/server/src/adapters/mod.rs @@ -6,8 +6,8 @@ //! Each framework has utilies for some or all of the following: //! - Server functions //! - A generic way to register server functions -//! - A way to register server functions with a custom handler that allows users to pass in a custom [`DioxusServerContext`] based on the state of the server framework. -//! - A way to register static WASM files that is accepts [`ServeConfig`] +//! - A way to register server functions with a custom handler that allows users to pass in a custom [`crate::server_context::DioxusServerContext`] based on the state of the server framework. +//! - A way to register static WASM files that is accepts [`crate::serve_config::ServeConfig`] //! - A hot reloading web socket that intigrates with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload) #[cfg(feature = "axum")] diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 7ef232c23..4738ef00f 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -1,8 +1,8 @@ //! Fullstack utilities for the [`dioxus`](https://dioxuslabs.com) framework. //! //! # Features -//! - Intigrations with the [axum](crate::adapters::axum_adapter), [salvo](crate::adapters::salvo_adapters), and [warp](crate::adapters::warp_adapters) server frameworks with utilities for serving and rendering Dioxus applications. -//! - Server functions that allow you to call code on the server from the client as if it were a normal function. +//! - Intigrations with the [axum](crate::adapters::axum_adapter), [salvo](crate::adapters::salvo_adapter), and [warp](crate::adapters::warp_adapter) server frameworks with utilities for serving and rendering Dioxus applications. +//! - [Server functions](crate::prelude::server) that allow you to call code on the server from the client as if it were a normal function. //! - Instant RSX Hot reloading with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload). //! //! # Example @@ -60,6 +60,8 @@ #[allow(unused)] use dioxus_core::prelude::*; +pub use adapters::*; + mod adapters; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] mod hot_reload; diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs index 6f985a39a..643f25c9f 100644 --- a/packages/server/src/server_fn.rs +++ b/packages/server/src/server_fn.rs @@ -82,7 +82,7 @@ pub enum ServerRegistrationFnError { /// Server functions are created using the `server` macro. /// /// The function should be registered by calling `ServerFn::register()`. The set of server functions -/// can be queried on the server for routing purposes by calling [ServerFunctionRegistry::get]. +/// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get]. /// /// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. pub trait ServerFn: server_fn::ServerFn { From 0e445c9f5958eb5b2e64cf9fbe22e3b56978b3df Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 13:34:34 -0500 Subject: [PATCH 395/895] add desktop server functions example --- Cargo.toml | 3 +- .../server/examples/axum-desktop/.gitignore | 2 + .../server/examples/axum-desktop/Cargo.toml | 31 ++++++++++++++ .../examples/axum-desktop/src/client.rs | 13 ++++++ .../server/examples/axum-desktop/src/lib.rs | 40 +++++++++++++++++++ .../examples/axum-desktop/src/server.rs | 23 +++++++++++ .../examples/axum-hello-world/Cargo.toml | 3 +- 7 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 packages/server/examples/axum-desktop/.gitignore create mode 100644 packages/server/examples/axum-desktop/Cargo.toml create mode 100644 packages/server/examples/axum-desktop/src/client.rs create mode 100644 packages/server/examples/axum-desktop/src/lib.rs create mode 100644 packages/server/examples/axum-desktop/src/server.rs diff --git a/Cargo.toml b/Cargo.toml index 720b9e274..a5beb4aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,9 +25,10 @@ members = [ "packages/server", "packages/server/server-macro", "packages/server/examples/axum-hello-world", + "packages/server/examples/axum-router", + "packages/server/examples/axum-desktop", "packages/server/examples/salvo-hello-world", "packages/server/examples/warp-hello-world", - "packages/server/examples/axum-router", "docs/guide", ] diff --git a/packages/server/examples/axum-desktop/.gitignore b/packages/server/examples/axum-desktop/.gitignore new file mode 100644 index 000000000..6047329c6 --- /dev/null +++ b/packages/server/examples/axum-desktop/.gitignore @@ -0,0 +1,2 @@ +dist +target \ No newline at end of file diff --git a/packages/server/examples/axum-desktop/Cargo.toml b/packages/server/examples/axum-desktop/Cargo.toml new file mode 100644 index 000000000..817202bd1 --- /dev/null +++ b/packages/server/examples/axum-desktop/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "axum-desktop" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] + +[dependencies] +dioxus-desktop = { path = "../../../desktop", optional = true } +dioxus = { path = "../../../dioxus" } +dioxus-router = { path = "../../../router" } +dioxus-server = { path = "../../" } +axum = { version = "0.6.12", optional = true } +tokio = { version = "1.27.0", features = ["full"], optional = true } +serde = "1.0.159" + +[features] +default = [] +ssr = ["axum", "tokio", "dioxus-server/axum"] +desktop = ["dioxus-desktop"] + +[[bin]] +name = "client" +path = "src/client.rs" +required-features = ["desktop"] + +[[bin]] +name = "server" +path = "src/server.rs" +required-features = ["ssr"] diff --git a/packages/server/examples/axum-desktop/src/client.rs b/packages/server/examples/axum-desktop/src/client.rs new file mode 100644 index 000000000..588cf2003 --- /dev/null +++ b/packages/server/examples/axum-desktop/src/client.rs @@ -0,0 +1,13 @@ +// Run with: +// ```bash +// cargo run --bin client --features="desktop" +// ``` + +use axum_desktop::*; +use dioxus_server::prelude::server_fn::set_server_url; + +fn main() { + // Set the url of the server where server functions are hosted. + set_server_url("http://localhost:8080"); + dioxus_desktop::launch(app) +} diff --git a/packages/server/examples/axum-desktop/src/lib.rs b/packages/server/examples/axum-desktop/src/lib.rs new file mode 100644 index 000000000..3bae1dcde --- /dev/null +++ b/packages/server/examples/axum-desktop/src/lib.rs @@ -0,0 +1,40 @@ +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +pub fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + let text = use_state(cx, || "...".to_string()); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![text]; + async move { + if let Ok(data) = get_server_data().await { + println!("Client received: {}", data); + text.set(data.clone()); + post_server_data(data).await.unwrap(); + } + } + }, + "Run a server function" + } + "Server said: {text}" + }) +} + +#[server(PostServerData)] +async fn post_server_data(data: String) -> Result<(), ServerFnError> { + println!("Server received: {}", data); + + Ok(()) +} + +#[server(GetServerData)] +async fn get_server_data() -> Result { + Ok("Hello from the server!".to_string()) +} diff --git a/packages/server/examples/axum-desktop/src/server.rs b/packages/server/examples/axum-desktop/src/server.rs new file mode 100644 index 000000000..ff607dbcd --- /dev/null +++ b/packages/server/examples/axum-desktop/src/server.rs @@ -0,0 +1,23 @@ +// Run with: +// ```bash +// cargo run --bin server --features="ssr" +// ``` + +use axum_desktop::*; +use dioxus_server::prelude::*; + +#[tokio::main] +async fn main() { + PostServerData::register().unwrap(); + GetServerData::register().unwrap(); + + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .register_server_fns("") + .into_make_service(), + ) + .await + .unwrap(); +} diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index 50d5e05b3..fd1f051d1 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -9,7 +9,6 @@ publish = false [dependencies] dioxus-web = { path = "../../../web", features=["hydrate"], optional = true } dioxus = { path = "../../../dioxus" } -dioxus-router = { path = "../../../router" } dioxus-server = { path = "../../" } axum = { version = "0.6.12", optional = true } tokio = { version = "1.27.0", features = ["full"], optional = true } @@ -18,4 +17,4 @@ serde = "1.0.159" [features] default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum"] -web = ["dioxus-web", "dioxus-router/web"] +web = ["dioxus-web"] From 53c85851076462cd002a6c85135cca5f7bdbe1b0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 13:58:54 -0500 Subject: [PATCH 396/895] Add dixous-server README --- packages/server/Cargo.toml | 6 ++ packages/server/README.md | 103 ++++++++++++++++++++++++ packages/server/server-macro/src/lib.rs | 6 +- packages/server/src/lib.rs | 65 +-------------- 4 files changed, 116 insertions(+), 64 deletions(-) create mode 100644 packages/server/README.md diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index fddeccbde..8709cb57d 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -2,6 +2,12 @@ name = "dioxus-server" version = "0.1.0" edition = "2021" +description = "Fullstack Dioxus Utilities" +license = "MIT/Apache-2.0" +repository = "https://github.com/DioxusLabs/dioxus/" +homepage = "https://dioxuslabs.com" +documentation = "https://dioxuslabs.com" +keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/server/README.md b/packages/server/README.md new file mode 100644 index 000000000..92f878684 --- /dev/null +++ b/packages/server/README.md @@ -0,0 +1,103 @@ +# Dioxus Server + +[![Crates.io][crates-badge]][crates-url] +[![MIT licensed][mit-badge]][mit-url] +[![Build Status][actions-badge]][actions-url] +[![Discord chat][discord-badge]][discord-url] + +[crates-badge]: https://img.shields.io/crates/v/dioxus-server.svg +[crates-url]: https://crates.io/crates/dioxus-server +[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-url]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE +[actions-badge]: https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg +[actions-url]: https://github.com/dioxuslabs/dioxus/actions?query=workflow%3ACI+branch%3Amaster +[discord-badge]: https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square +[discord-url]: https://discord.gg/XgGxMSkvUM + +[Website](https://dioxuslabs.com) | +[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) | +[API Docs](https://docs.rs/dioxus-server/latest/dioxus_sever) | +[Chat](https://discord.gg/XgGxMSkvUM) + +Fullstack utilities for the [`Dioxus`](https://dioxuslabs.com) framework. + +# Features + +- Intigrations with the [Axum](https::/docs.rs/dioxus-server/latest/dixous_server/axum_adapter/index.html), [Salvo](https::/docs.rs/dioxus-server/latest/dixous_server/salvo_adapter/index.html), and [Warp](https::/docs.rs/dioxus-server/latest/dixous_server/warp_adapter/index.html) server frameworks with utilities for serving and rendering Dioxus applications. +- [Server functions](https::/docs.rs/dioxus-server/latest/dixous_server/prelude/attr.server.html) allow you to call code on the server from the client as if it were a normal function. +- Instant RSX Hot reloading with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload). + +# Example + +Full stack Dioxus in under 50 lines of code + +```rust +#![allow(non_snake_case)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + GetMeaning::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + warp::serve( + // Automatically handles server side rendering, hot reloading intigration, and hosting server functions + serve_dioxus_application( + "", + ServeConfigBuilder::new(app, ()), + ) + ) + .run(([127, 0, 0, 1], 8080)) + .await; + }); + } +} + +fn app(cx: Scope) -> Element { + let meaning = use_state(cx, || None); + cx.render(rsx! { + button { + onclick: move |_| { + to_owned![meaning]; + async move { + if let Ok(data) = get_meaning("life the universe and everything".into()).await { + meaning.set(data); + } + } + }, + "Run a server function" + } + "Server said: {meaning:?}" + }) +} + +// This code will only run on the server +#[server(GetMeaning)] +async fn get_meaning(of: String) -> Result, ServerFnError> { + Ok(of.contains("life").then(|| 42)) +} +``` + +## Getting Started + +To get started with full stack Dioxus, check out our [getting started guide](https://dioxuslabs.com/docs/nightly/guide/en/getting_started/ssr.html), or the [full stack examples](https://github.com/DioxusLabs/dioxus/tree/master/packages/server/examples). + +## Contributing + +- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues). +- Join the discord and ask questions! + +## License + +This project is licensed under the [MIT license]. + +[mit license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Dioxus by you shall be licensed as MIT without any additional +terms or conditions. diff --git a/packages/server/server-macro/src/lib.rs b/packages/server/server-macro/src/lib.rs index e34a440d4..14fc0ac77 100644 --- a/packages/server/server-macro/src/lib.rs +++ b/packages/server/server-macro/src/lib.rs @@ -19,7 +19,7 @@ use server_fn_macro::*; /// work without WebAssembly, the encoding must be `"Url"`. /// /// The server function itself can take any number of arguments, each of which should be serializable -/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html), +/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus-server/latest/dixous_server/prelude/struct.DioxusServerContext.html), /// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other /// server-side context into the server function. /// @@ -50,8 +50,8 @@ use server_fn_macro::*; /// They are serialized as an `application/x-www-form-urlencoded` /// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor` /// using [`cbor`](https://docs.rs/cbor/latest/cbor/). -/// - **The [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html) comes from the server.** Optionally, the first argument of a server function -/// can be a [DioxusServerContext](https::/docs.rs/dioxus_server/latest/dixous_server/prelude/struct.DioxusServerContext.html). This scope can be used to inject dependencies like the HTTP request +/// - **The [DioxusServerContext](https::/docs.rs/dioxus-server/latest/dixous_server/prelude/struct.DioxusServerContext.html) comes from the server.** Optionally, the first argument of a server function +/// can be a [DioxusServerContext](https::/docs.rs/dioxus-server/latest/dixous_server/prelude/struct.DioxusServerContext.html). This scope can be used to inject dependencies like the HTTP request /// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client. #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 4738ef00f..c61b26429 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -1,64 +1,7 @@ -//! Fullstack utilities for the [`dioxus`](https://dioxuslabs.com) framework. -//! -//! # Features -//! - Intigrations with the [axum](crate::adapters::axum_adapter), [salvo](crate::adapters::salvo_adapter), and [warp](crate::adapters::warp_adapter) server frameworks with utilities for serving and rendering Dioxus applications. -//! - [Server functions](crate::prelude::server) that allow you to call code on the server from the client as if it were a normal function. -//! - Instant RSX Hot reloading with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload). -//! -//! # Example -//! Full stack Dioxus in under 50 lines of code -//! ```rust -//! #![allow(non_snake_case)] -//! use dioxus::prelude::*; -//! use dioxus_server::prelude::*; -//! -//! fn main() { -//! #[cfg(feature = "web")] -//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); -//! #[cfg(feature = "ssr")] -//! { -//! GetMeaning::register().unwrap(); -//! tokio::runtime::Runtime::new() -//! .unwrap() -//! .block_on(async move { -//! warp::serve(serve_dioxus_application( -//! "", -//! ServeConfigBuilder::new(app, ()), -//! )) -//! .run(([127, 0, 0, 1], 8080)) -//! .await; -//! }); -//! } -//! } -//! -//! fn app(cx: Scope) -> Element { -//! let meaning = use_state(cx, || None); -//! cx.render(rsx! { -//! button { -//! onclick: move |_| { -//! to_owned![meaning]; -//! async move { -//! if let Ok(data) = get_meaning("life the universe and everything".into()).await { -//! meaning.set(data); -//! } -//! } -//! }, -//! "Run a server function" -//! } -//! "Server said: {meaning:?}" -//! }) -//! } -//! -//! // This code will only run on the server -//! #[server(GetMeaning)] -//! async fn get_meaning(of: String) -> Result, ServerFnError> { -//! Ok(of.contains("life").then(|| 42)) -//! } -//! ``` - -#![warn(missing_docs)] -#[allow(unused)] -use dioxus_core::prelude::*; +#![doc = include_str!("../README.md")] +#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] +#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] +#![deny(missing_docs)] pub use adapters::*; From 4c22d5809e92014d19628db467ad7eb41345d3bd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 16:06:23 -0500 Subject: [PATCH 397/895] add fullstack section to the getting started guide --- docs/guide/Cargo.toml | 3 +- docs/guide/examples/server.rs | 132 ++++++++++++++++++ docs/guide/src/en/SUMMARY.md | 1 + .../guide/src/en/getting_started/fullstack.md | 115 +++++++++++++++ .../src/en/getting_started/hot_reload.md | 15 +- docs/guide/src/en/getting_started/ssr.md | 21 +-- docs/guide/src/en/getting_started/web.md | 6 +- 7 files changed, 273 insertions(+), 20 deletions(-) create mode 100644 docs/guide/examples/server.rs create mode 100644 docs/guide/src/en/getting_started/fullstack.md diff --git a/docs/guide/Cargo.toml b/docs/guide/Cargo.toml index 227bdfa35..00a5c7543 100644 --- a/docs/guide/Cargo.toml +++ b/docs/guide/Cargo.toml @@ -16,6 +16,7 @@ dioxus-native-core-macro = { path = "../../packages/native-core-macro" } dioxus-router = { path = "../../packages/router" } dioxus-liveview = { path = "../../packages/liveview", features = ["axum"] } dioxus-tui = { path = "../../packages/dioxus-tui" } +dioxus-server = { path = "../../packages/server" } fermi = { path = "../../packages/fermi" } shipyard = "0.6.2" @@ -23,5 +24,5 @@ shipyard = "0.6.2" # dioxus = { path = "../../packages/dioxus", features = ["desktop", "web", "ssr", "router", "fermi", "tui"] } serde = { version = "1.0.138", features=["derive"] } reqwest = { version = "0.11.11", features = ["json"] } -tokio = { version = "1.19.2" , features=[]} +tokio = { version = "1.19.2", features = ["full"] } axum = { version = "0.6.1", features = ["ws"] } diff --git a/docs/guide/examples/server.rs b/docs/guide/examples/server.rs new file mode 100644 index 000000000..80e74a919 --- /dev/null +++ b/docs/guide/examples/server.rs @@ -0,0 +1,132 @@ +mod basic { + // ANCHOR: basic + #![allow(non_snake_case)] + use dioxus::prelude::*; + use dioxus_server::prelude::*; + + #[tokio::main] + async fn main() { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + } + + fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + }) + } + // ANCHOR_END: basic +} + +mod hydration { + // ANCHOR: hydration + #![allow(non_snake_case)] + use dioxus::prelude::*; + use dioxus_server::prelude::*; + + fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + }); + } + } + + fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + }) + } + // ANCHOR_END: hydration +} + +mod server_function { + // ANCHOR: server_function + #![allow(non_snake_case)] + use dioxus::prelude::*; + use dioxus_server::prelude::*; + + fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + // Register the server function before starting the server + DoubleServer::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + // Serve Dioxus application automatically recognizes server functions and adds them to the API + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + }); + } + } + + fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![count]; + async move { + // Call the server function just like a local async function + if let Ok(new_count) = double_server(*count.current()).await { + count.set(new_count); + } + } + }, + "Double" + } + }) + } + + #[server(DoubleServer)] + async fn double_server(number: u32) -> Result { + // Perform some expensive computation or access a database on the server + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let result = number * 2; + println!("server calculated {result}"); + Ok(result) + } + // ANCHOR_END: server_function +} diff --git a/docs/guide/src/en/SUMMARY.md b/docs/guide/src/en/SUMMARY.md index f9f31ed52..b61a36117 100644 --- a/docs/guide/src/en/SUMMARY.md +++ b/docs/guide/src/en/SUMMARY.md @@ -6,6 +6,7 @@ - [Desktop](getting_started/desktop.md) - [Web](getting_started/web.md) - [Server-Side Rendering](getting_started/ssr.md) + - [Fullstack](getting_started/fullstack.md) - [Liveview](getting_started/liveview.md) - [Terminal UI](getting_started/tui.md) - [Mobile](getting_started/mobile.md) diff --git a/docs/guide/src/en/getting_started/fullstack.md b/docs/guide/src/en/getting_started/fullstack.md new file mode 100644 index 000000000..b132de319 --- /dev/null +++ b/docs/guide/src/en/getting_started/fullstack.md @@ -0,0 +1,115 @@ +> This guide assumes you read the [Web](web.md) guide and installed the [Dioxus-cli](https://github.com/DioxusLabs/cli) + +# Fullstack development + +We can combine the `dioxus-web` renderer with the `dioxus-ssr` renderer to create a full-stack Dioxus application. By combining server-side rendering with client-side hydration we can create an application that is initially rendered on the server and then hydrates the application on the client. Server-side rendering results in a fast first paint and make our page SEO-friendly. Client-side hydration makes our page responsive once the application has fully loaded. + +To help make full-stack development easier, Dioxus provides a `dioxus-server` crate that integrates with popular web frameworks with utilities for full-stack development. + +## Setup + +For this guide, we're going to show how to use Dioxus with [Axum](https://docs.rs/axum/latest/axum/), but `dioxus-server` also integrates with the [Warp](https://docs.rs/warp/latest/warp/) and [Salvo](https://docs.rs/salvo/latest/salvo/) web frameworks. + +Make sure you have Rust and Cargo installed, and then create a new project: + +```shell +cargo new --bin demo +cd demo +``` + +Add `dioxus` and `dioxus-server` as dependencies: + +```shell +cargo add dioxus +cargo add dioxus-server --features axum, ssr +``` + +Next, add all the Axum dependencies. This will be different if you're using a different Web Framework + +```shell +cargo add tokio --features full +cargo add axum +``` + +Your dependencies should look roughly like this: + +```toml +[dependencies] +axum = "*" +dioxus = { version = "*" } +dioxus-server = { version = "*", features = ["axum", "ssr"] } +tokio = { version = "*", features = ["full"] } +``` + +Now, set up your Axum app to serve the Dioxus app. + +```rust +{{#include ../../../examples/server.rs:basic}} +``` + +Now, run your app with `cargo run` and open `http://localhost:8080` in your browser. You should see a server-side rendered page with a counter. + +## Hydration + +Right now, the page is static. We can't interact with the buttons. To fix this, we can hydrate the page with `dioxus-web`. + +First, modify your `Cargo.toml` to include two features, one for the server called `ssr`, and one for the client called `web`. + +```toml +[dependencies] +# Common dependancies +dioxus = { version = "*" } +dioxus-server = { version = "*" } + +# Web dependancies +dioxus-web = { version = "*", features=["hydrate"], optional = true } + +# Server dependancies +axum = { version = "0.6.12", optional = true } +tokio = { version = "1.27.0", features = ["full"], optional = true } + +[features] +default = [] +ssr = ["axum", "tokio", "dioxus-server/axum"] +web = ["dioxus-web"] +``` + +Next, we need to modify our `main.rs` to use either hydrate on the client or render on the server depending on the active features. + +```rust +{{#include ../../../examples/server.rs:hydration}} +``` + +Now, build your client-side bundle with `dioxus build --features web` and run your server with `cargo run --features ssr`. You should see the same page as before, but now you can interact with the buttons! + +## Communicating with the server + +`dixous-server` provides server functions that allow you to call an automatically generated API on the server from the client as if it were a local function. + +To make a server function, simply add the `#[server(YourUniqueType)]` attribute to a function. The function must: + +- Be an async function +- Have arguments and a return type that both implement serialize and deserialize (with [serde](https://serde.rs/)). +- Return a `Result` with an error type of ServerFnError + +You must call `register` on the type you passed into the server macro in your main function before starting your server to tell Dioxus about the server function. + +Let's add a server function to our app that allows us to multiply the count by a number on the server. + +First, add serde as a dependency: + +```shell +cargo add serde +``` + +Next, add the server function to your `main.rs`: + +```rust +{{#include ../../../examples/server.rs:server_function}} +``` + +Now, build your client-side bundle with `dioxus build --features web` and run your server with `cargo run --features ssr`. You should see a new button that multiplies the count by 2. + +## Conclusion + +That's it! You've created a full-stack Dioxus app. You can find more examples of full-stack apps and information about how to integrate with other frameworks and desktop renderers in the [dioxus-server examples directory](https://github.com/DioxusLabs/dioxus/tree/master/packages/server/examples). diff --git a/docs/guide/src/en/getting_started/hot_reload.md b/docs/guide/src/en/getting_started/hot_reload.md index 599ce57da..2ebf5e4aa 100644 --- a/docs/guide/src/en/getting_started/hot_reload.md +++ b/docs/guide/src/en/getting_started/hot_reload.md @@ -5,28 +5,35 @@ 3. Currently the cli only implements hot reloading for the web renderer. For TUI, desktop, and LiveView you can use the hot reload macro instead. # Web + For the web renderer, you can use the dioxus cli to serve your application with hot reloading enabled. ## Setup + Install [dioxus-cli](https://github.com/DioxusLabs/cli). Hot reloading is automatically enabled when using the web renderer on debug builds. ## Usage + 1. Run: -```bash + +```bash dioxus serve --hot-reload ``` + 2. Change some code within a rsx or render macro 3. Open your localhost in a browser 4. Save and watch the style change without recompiling -# Desktop/Liveview/TUI +# Desktop/Liveview/TUI/Server + For desktop, LiveView, and tui, you can place the hot reload macro at the top of your main function to enable hot reloading. Hot reloading is automatically enabled on debug builds. For more information about hot reloading on native platforms and configuration options see the [dioxus-hot-reload](https://crates.io/crates/dioxus-hot-reload) crate. ## Setup + Add the following to your main function: ```rust @@ -37,13 +44,17 @@ fn main() { ``` ## Usage + 1. Run: + ```bash cargo run ``` + 2. Change some code within a rsx or render macro 3. Save and watch the style change without recompiling # Limitations + 1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression. 2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed. diff --git a/docs/guide/src/en/getting_started/ssr.md b/docs/guide/src/en/getting_started/ssr.md index 9654003cf..f78623003 100644 --- a/docs/guide/src/en/getting_started/ssr.md +++ b/docs/guide/src/en/getting_started/ssr.md @@ -1,17 +1,6 @@ # Server-Side Rendering -The Dioxus VirtualDom can be rendered server-side. - -[Example: Dioxus DocSite](https://github.com/dioxusLabs/docsite) - -## Multithreaded Support - -The Dioxus VirtualDom, sadly, is not currently `Send`. Internally, we use quite a bit of interior mutability which is not thread-safe. This means you can't easily use Dioxus with most web frameworks like Tide, Rocket, Axum, etc. - -To solve this, you'll want to spawn a VirtualDom on its own thread and communicate with it via channels. - -When working with web frameworks that require `Send`, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to create a pool of VirtualDoms. - +For lower-level control over the rendering process, you can use the `dioxus-ssr` crate directly. This can be useful when integrating with a web framework that `dioxus-server` does not support, or pre-rendering pages. ## Setup @@ -21,7 +10,7 @@ Make sure you have Rust and Cargo installed, and then create a new project: ```shell cargo new --bin demo -cd app +cd demo ``` Add Dioxus and the ssr renderer as dependencies: @@ -99,6 +88,8 @@ async fn app_endpoint() -> Html { } ``` -And that's it! +## Multithreaded Support -> You might notice that you cannot hold the VirtualDom across an await point. Dioxus is currently not ThreadSafe, so it _must_ remain on the thread it started. We are working on loosening this requirement. \ No newline at end of file +The Dioxus VirtualDom, sadly, is not currently `Send`. Internally, we use quite a bit of interior mutability which is not thread-safe. +When working with web frameworks that require `Send`, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to spawn a VirtualDom on its own thread and communicate with it via channels or create a pool of VirtualDoms. +You might notice that you cannot hold the VirtualDom across an await point. Because Dioxus is currently not ThreadSafe, it _must_ remain on the thread it started. We are working on loosening this requirement. diff --git a/docs/guide/src/en/getting_started/web.md b/docs/guide/src/en/getting_started/web.md index 76e3b9541..e8a1f3da2 100644 --- a/docs/guide/src/en/getting_started/web.md +++ b/docs/guide/src/en/getting_started/web.md @@ -5,6 +5,7 @@ Build single-page applications that run in the browser with Dioxus. To run on th A build of Dioxus for the web will be roughly equivalent to the size of a React build (70kb vs 65kb) but it will load significantly faster because [WebAssembly can be compiled as it is streamed](https://hacks.mozilla.org/2018/01/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler/). Examples: + - [TodoMVC](https://github.com/DioxusLabs/example-projects/tree/master/todomvc) - [ECommerce](https://github.com/DioxusLabs/example-projects/tree/master/ecommerce-site) @@ -17,7 +18,7 @@ Examples: The Web is the best-supported target platform for Dioxus. - Because your app will be compiled to WASM you have access to browser APIs through [wasm-bingen](https://rustwasm.github.io/docs/wasm-bindgen/introduction.html). -- Dioxus provides hydration to resume apps that are rendered on the server. See the [hydration example](https://github.com/DioxusLabs/dioxus/blob/master/packages/web/examples/hydrate.rs) for more details. +- Dioxus provides hydration to resume apps that are rendered on the server. See the [fullstack](fullstack.md) getting started guide for more information. ## Tooling @@ -28,6 +29,7 @@ cargo install dioxus-cli ``` Make sure the `wasm32-unknown-unknown` target for rust is installed: + ```shell rustup target add wasm32-unknown-unknown ``` @@ -49,11 +51,11 @@ cargo add dioxus-web ``` Edit your `main.rs`: + ```rust {{#include ../../../examples/hello_world_web.rs}} ``` - And to serve our app: ```bash From 219af51526ffb758fbf99a4113099639bb56e398 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 3 Apr 2023 17:39:09 -0500 Subject: [PATCH 398/895] fix cargo check --- docs/guide/examples/hydration.rs | 34 +++++ docs/guide/examples/server.rs | 132 ------------------ docs/guide/examples/server_basic.rs | 30 ++++ docs/guide/examples/server_function.rs | 58 ++++++++ .../guide/src/en/getting_started/fullstack.md | 6 +- packages/router/src/components/router.rs | 7 +- packages/server/Cargo.toml | 2 +- packages/server/server-macro/Cargo.toml | 2 +- packages/server/src/lib.rs | 4 +- packages/server/src/render.rs | 3 +- 10 files changed, 136 insertions(+), 142 deletions(-) create mode 100644 docs/guide/examples/hydration.rs delete mode 100644 docs/guide/examples/server.rs create mode 100644 docs/guide/examples/server_basic.rs create mode 100644 docs/guide/examples/server_function.rs diff --git a/docs/guide/examples/hydration.rs b/docs/guide/examples/hydration.rs new file mode 100644 index 000000000..f3c9bca8f --- /dev/null +++ b/docs/guide/examples/hydration.rs @@ -0,0 +1,34 @@ +#![allow(non_snake_case, unused)] +use dioxus::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + use dioxus_server::prelude::*; + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + }); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + }) +} diff --git a/docs/guide/examples/server.rs b/docs/guide/examples/server.rs deleted file mode 100644 index 80e74a919..000000000 --- a/docs/guide/examples/server.rs +++ /dev/null @@ -1,132 +0,0 @@ -mod basic { - // ANCHOR: basic - #![allow(non_snake_case)] - use dioxus::prelude::*; - use dioxus_server::prelude::*; - - #[tokio::main] - async fn main() { - let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - axum::Server::bind(&addr) - .serve( - axum::Router::new() - .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) - .into_make_service(), - ) - .await - .unwrap(); - } - - fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); - - cx.render(rsx! { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - }) - } - // ANCHOR_END: basic -} - -mod hydration { - // ANCHOR: hydration - #![allow(non_snake_case)] - use dioxus::prelude::*; - use dioxus_server::prelude::*; - - fn main() { - #[cfg(feature = "web")] - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); - #[cfg(feature = "ssr")] - { - tokio::runtime::Runtime::new() - .unwrap() - .block_on(async move { - let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - axum::Server::bind(&addr) - .serve( - axum::Router::new() - .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) - .into_make_service(), - ) - .await - .unwrap(); - }); - } - } - - fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); - - cx.render(rsx! { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - }) - } - // ANCHOR_END: hydration -} - -mod server_function { - // ANCHOR: server_function - #![allow(non_snake_case)] - use dioxus::prelude::*; - use dioxus_server::prelude::*; - - fn main() { - #[cfg(feature = "web")] - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); - #[cfg(feature = "ssr")] - { - // Register the server function before starting the server - DoubleServer::register().unwrap(); - tokio::runtime::Runtime::new() - .unwrap() - .block_on(async move { - let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - axum::Server::bind(&addr) - .serve( - axum::Router::new() - // Serve Dioxus application automatically recognizes server functions and adds them to the API - .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) - .into_make_service(), - ) - .await - .unwrap(); - }); - } - } - - fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); - - cx.render(rsx! { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - button { - onclick: move |_| { - to_owned![count]; - async move { - // Call the server function just like a local async function - if let Ok(new_count) = double_server(*count.current()).await { - count.set(new_count); - } - } - }, - "Double" - } - }) - } - - #[server(DoubleServer)] - async fn double_server(number: u32) -> Result { - // Perform some expensive computation or access a database on the server - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - let result = number * 2; - println!("server calculated {result}"); - Ok(result) - } - // ANCHOR_END: server_function -} diff --git a/docs/guide/examples/server_basic.rs b/docs/guide/examples/server_basic.rs new file mode 100644 index 000000000..bd6cf78e6 --- /dev/null +++ b/docs/guide/examples/server_basic.rs @@ -0,0 +1,30 @@ +#![allow(non_snake_case, unused)] +use dioxus::prelude::*; + +#[tokio::main] +async fn main() { + #[cfg(feature = "ssr")] + { + use dioxus_server::prelude::*; + + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + }) +} diff --git a/docs/guide/examples/server_function.rs b/docs/guide/examples/server_function.rs new file mode 100644 index 000000000..106c54c3f --- /dev/null +++ b/docs/guide/examples/server_function.rs @@ -0,0 +1,58 @@ +#![allow(non_snake_case, unused)] +use dioxus::prelude::*; +use dioxus_server::prelude::*; + +fn main() { + #[cfg(feature = "web")] + dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + #[cfg(feature = "ssr")] + { + // Register the server function before starting the server + DoubleServer::register().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async move { + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + axum::Server::bind(&addr) + .serve( + axum::Router::new() + // Serve Dioxus application automatically recognizes server functions and adds them to the API + .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .into_make_service(), + ) + .await + .unwrap(); + }); + } +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || 0); + + cx.render(rsx! { + h1 { "High-Five counter: {count}" } + button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count -= 1, "Down low!" } + button { + onclick: move |_| { + to_owned![count]; + async move { + // Call the server function just like a local async function + if let Ok(new_count) = double_server(*count.current()).await { + count.set(new_count); + } + } + }, + "Double" + } + }) +} + +#[server(DoubleServer)] +async fn double_server(number: u32) -> Result { + // Perform some expensive computation or access a database on the server + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let result = number * 2; + println!("server calculated {result}"); + Ok(result) +} diff --git a/docs/guide/src/en/getting_started/fullstack.md b/docs/guide/src/en/getting_started/fullstack.md index b132de319..f01d8dd30 100644 --- a/docs/guide/src/en/getting_started/fullstack.md +++ b/docs/guide/src/en/getting_started/fullstack.md @@ -44,7 +44,7 @@ tokio = { version = "*", features = ["full"] } Now, set up your Axum app to serve the Dioxus app. ```rust -{{#include ../../../examples/server.rs:basic}} +{{#include ../../../examples/server_basic.rs}} ``` Now, run your app with `cargo run` and open `http://localhost:8080` in your browser. You should see a server-side rendered page with a counter. @@ -77,7 +77,7 @@ web = ["dioxus-web"] Next, we need to modify our `main.rs` to use either hydrate on the client or render on the server depending on the active features. ```rust -{{#include ../../../examples/server.rs:hydration}} +{{#include ../../../examples/hydration.rs}} ``` Now, build your client-side bundle with `dioxus build --features web` and run your server with `cargo run --features ssr`. You should see the same page as before, but now you can interact with the buttons! @@ -105,7 +105,7 @@ cargo add serde Next, add the server function to your `main.rs`: ```rust -{{#include ../../../examples/server.rs:server_function}} +{{#include ../../../examples/server_function.rs}} ``` Now, build your client-side bundle with `dioxus build --features web` and run your server with `cargo run --features ssr`. You should see a new button that multiplies the count by 2. diff --git a/packages/router/src/components/router.rs b/packages/router/src/components/router.rs index b027386c5..8d5365c35 100644 --- a/packages/router/src/components/router.rs +++ b/packages/router/src/components/router.rs @@ -29,8 +29,9 @@ pub struct RouterProps<'a> { pub active_class: Option<&'a str>, /// Set the initial url. - #[props(!optional, into)] - pub initial_url: Option, + // This is Option> because we want to be able to either omit the prop or pass in Option + #[props(into)] + pub initial_url: Option>, } /// A component that conditionally renders children based on the current location of the app. @@ -46,7 +47,7 @@ pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element { RouterCfg { base_url: cx.props.base_url.map(|s| s.to_string()), active_class: cx.props.active_class.map(|s| s.to_string()), - initial_url: cx.props.initial_url.clone(), + initial_url: cx.props.initial_url.clone().flatten(), }, )) }); diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 8709cb57d..18633e97a 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"] [dependencies] # server functions server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "a9e6590b5e7f1c0b01da7db7b86719cb18a4aaa1", features = ["stable"] } -server_macro = { path = "server-macro" } +dioxus_server_macro = { path = "server-macro" } # warp warp = { version = "0.3.3", optional = true } diff --git a/packages/server/server-macro/Cargo.toml b/packages/server/server-macro/Cargo.toml index d03c5274c..45b0ec3c6 100644 --- a/packages/server/server-macro/Cargo.toml +++ b/packages/server/server-macro/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "server_macro" +name = "dioxus_server_macro" version = "0.1.0" edition = "2021" diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index c61b26429..df2735cf4 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -24,11 +24,13 @@ pub mod prelude { #[cfg(feature = "warp")] pub use crate::adapters::warp_adapter::*; #[cfg(feature = "ssr")] + pub use crate::render::SSRState; + #[cfg(feature = "ssr")] pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; pub use crate::server_context::DioxusServerContext; pub use crate::server_fn::ServerFn; #[cfg(feature = "ssr")] pub use crate::server_fn::ServerFnTraitObj; + pub use dioxus_server_macro::*; pub use server_fn::{self, ServerFn as _, ServerFnError}; - pub use server_macro::*; } diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 22e751ea8..8328be317 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -9,7 +9,7 @@ use crate::prelude::ServeConfig; /// State used in server side rendering. This utilizes a pool of [`dioxus_ssr::Renderer`]s to cache static templates between renders. #[derive(Clone)] -pub(crate) struct SSRState { +pub struct SSRState { // We keep a pool of renderers to avoid re-creating them on every request. They are boxed to make them very cheap to move renderers: Arc>, } @@ -23,6 +23,7 @@ impl Default for SSRState { } impl SSRState { + /// Render the application to HTML. pub fn render(&self, cfg: &ServeConfig

) -> String { let ServeConfig { app, props, index, .. From c2dd963d86ef745a260d311978866f8f0bdcbfcb Mon Sep 17 00:00:00 2001 From: Antonio Curavalea <112291302+arqalite@users.noreply.github.com> Date: Tue, 4 Apr 2023 05:12:52 +0300 Subject: [PATCH 399/895] doc: fermi: add counter example to readme (#931) * doc: add counter example to readme * doc: fermi: revert use_read --- packages/fermi/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/fermi/README.md b/packages/fermi/README.md index bd7d38ac4..f04ec5961 100644 --- a/packages/fermi/README.md +++ b/packages/fermi/README.md @@ -63,6 +63,26 @@ fn NameCard(cx: Scope) -> Element { } ``` +If needed, we can update the atom's value, based on itself: + +```rust, ignore +static COUNT: Atom = |_| 0; + +fn Counter(cx: Scope) -> Element { + let mut count = use_atom_state(cx, COUNT); + + cx.render(rsx!{ + p { + "{count}" + } + button { + onclick: move |_| count += 1, + "Increment counter" + } + }) +} +``` + It's that simple! ## Installation From 297c9a822e22921577d29f099f7acd73498baa70 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 5 Apr 2023 12:34:17 -0500 Subject: [PATCH 400/895] always update root id node refs --- packages/core/src/create.rs | 1 + packages/core/src/diff.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index 113fa7ae1..80561e937 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -35,6 +35,7 @@ fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> { } #[test] +#[cfg(debug_assertions)] fn sorting() { let r: [(usize, &[u8]); 5] = [ (0, &[0, 1]), diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 6f84b21aa..56a2d05de 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -148,6 +148,13 @@ impl<'b> VirtualDom { // Make sure the roots get transferred over while we're here right_template.root_ids.transfer(&left_template.root_ids); + + // Update the node refs + for i in 0..right_template.root_ids.len() { + if let Some(root_id) = right_template.root_ids.get(i) { + self.update_template(root_id, right_template); + } + } } fn diff_dynamic_node( From dc0df321b1caee0061d4867a20d56466395309a2 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 5 Apr 2023 13:00:27 -0700 Subject: [PATCH 401/895] Fix wry segfaulting by commenting out webcontext --- packages/desktop/src/webview.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index c5d8b4b42..a8e1d4995 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -33,8 +33,6 @@ pub fn build( )); } - let mut web_context = WebContext::new(cfg.data_dir.clone()); - let mut webview = WebViewBuilder::new(window) .unwrap() .with_transparent(cfg.window.window.transparent) @@ -54,8 +52,11 @@ pub fn build( .as_ref() .map(|handler| handler(window, evet)) .unwrap_or_default() - }) - .with_web_context(&mut web_context); + }); + + // These are commented out because wry is currently broken in wry + // let mut web_context = WebContext::new(cfg.data_dir.clone()); + // .with_web_context(&mut web_context); for (name, handler) in cfg.protocols.drain(..) { webview = webview.with_custom_protocol(name, handler) From 44c1e2e033344d970d5a14bcd17e742c3ae99871 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 5 Apr 2023 13:06:25 -0700 Subject: [PATCH 402/895] clippy --- packages/desktop/src/webview.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index a8e1d4995..099a2bd94 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -7,7 +7,7 @@ use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use wry; pub use wry::application as tao; use wry::application::window::Window; -use wry::webview::{WebContext, WebView, WebViewBuilder}; +use wry::webview::{WebView, WebViewBuilder}; pub fn build( cfg: &mut Config, From 44be89ff388c07bd8b3115bae714d0099ef8e457 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Thu, 6 Apr 2023 02:34:25 +0200 Subject: [PATCH 403/895] improve formatting with vs code extension --- extension/src/main.ts | 190 +++++++++++++++++++++++++++++----------- extension/tsconfig.json | 4 +- 2 files changed, 143 insertions(+), 51 deletions(-) diff --git a/extension/src/main.ts b/extension/src/main.ts index 1c75d3780..989220456 100644 --- a/extension/src/main.ts +++ b/extension/src/main.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import { spawn } from "child_process"; +import { TextEncoder } from 'util'; let serverPath: string = "dioxus"; @@ -19,7 +20,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand('extension.htmlToDioxusComponent', translateComponent), vscode.commands.registerCommand('extension.formatRsx', fmtSelection), vscode.commands.registerCommand('extension.formatRsxDocument', formatRsxDocument), - vscode.workspace.onWillSaveTextDocument(fmtDocument) + vscode.workspace.onWillSaveTextDocument(fmtDocumentOnSave) ); } @@ -81,9 +82,8 @@ function convertHtmlToRsxOnPaste() { function formatRsxDocument() { const editor = vscode.window.activeTextEditor; - if (editor) { - fmtDocument(); - } + if (!editor) return; + fmtDocument(editor.document); } function fmtSelection() { @@ -97,7 +97,11 @@ function fmtSelection() { return; } - const child_proc = spawn(serverPath, ["fmt", "--raw", unformatted.toString()]); + const fileDir = editor.document.fileName.slice(0, editor.document.fileName.lastIndexOf('\\')); + + const child_proc = spawn(serverPath, ["fmt", "--raw", unformatted.toString()], { + cwd: fileDir ? fileDir : undefined, + }); let result = ''; child_proc.stdout?.on('data', data => result += data); @@ -111,52 +115,140 @@ function fmtSelection() { }); } -function fmtDocument() { - const editor = vscode.window.activeTextEditor; - const document = editor?.document; - if (!document) return; - +function fmtDocumentOnSave(e: vscode.TextDocumentWillSaveEvent) { // check the settings to make sure format on save is configured - if (document.languageId === "rust" && document.uri.scheme === "file") { - const active_editor = vscode.window.activeTextEditor; - - if (active_editor?.document.fileName === document.fileName) { - const text = document.getText(); - const child_proc = spawn("dioxus", ["fmt", "-f", text]); - - let result = ''; - child_proc.stdout?.on('data', data => result += data); - - type RsxEdit = { - formatted: string, - start: number, - end: number - } - - child_proc.on('close', () => { - if (result.length > 0) { - let decoded: RsxEdit[] = JSON.parse(result); - - if (decoded.length > 0) { - active_editor.edit(editBuilder => { - decoded.map((edit) => { - editBuilder.replace(new vscode.Range( - document.positionAt(edit.start), - document.positionAt(edit.end) - ), edit.formatted); - }); - }, { - undoStopAfter: false, - undoStopBefore: false - }) - } - } - }); - - child_proc.on('error', (err) => { - vscode.window.showWarningMessage(`Errors occurred while translating. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); - }); + if (!vscode.workspace.getConfiguration('editor', e.document).get('formatOnSave')) { + return; + } + fmtDocument(e.document); +} +function fmtDocument(document: vscode.TextDocument) { + try { + if (document.languageId !== "rust" || document.uri.scheme !== "file") { + return; } + + const [editor,] = vscode.window.visibleTextEditors.filter(editor => editor.document.fileName === document.fileName); + if (!editor) return; // Need an editor to apply text edits. + + const text = document.getText(); + const fileDir = document.fileName.slice(0, document.fileName.lastIndexOf('\\')); + + const child_proc = spawn(serverPath, ["fmt", "--file", text], { + cwd: fileDir ? fileDir : undefined, + }); + + let result = ''; + child_proc.stdout?.on('data', data => result += data); + + type RsxEdit = { + formatted: string, + start: number, + end: number + } + + child_proc.on('close', () => { + if (child_proc.exitCode !== 0) { + vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed!\nDioxus-CLI exited with exit code ${child_proc.exitCode}\n\nData from Dioxus-CLI:\n${result}`); + return; + } + if (result.length === 0) return; + + // Used for error message: + const originalResult = result; + try { + // Only parse the last non empty line, to skip log warning messages: + const lines = result.replaceAll('\r\n', '\n').split('\n'); + const nonEmptyLines = lines.filter(line => line.trim().length !== 0); + result = nonEmptyLines[nonEmptyLines.length - 1] ?? ''; + + if (result.length === 0) return; + + let decoded: RsxEdit[] = JSON.parse(result); + if (decoded.length === 0) return; + + // Preform edits at the end of the file + // first (to not change previous text file + // offsets): + decoded.sort((a, b) => b.start - a.start); + + + // Convert from utf8 offsets to utf16 offsets used by VS Code: + + const utf8Text = new TextEncoder().encode(text); + const utf8ToUtf16Pos = (posUtf8: number) => { + const beforeTarget = utf8Text.slice(0, posUtf8 - 1); + + // Find the line of the position as well as the utf8 and + // utf16 indexes for the start of that line: + let startOfLineUtf8 = 0; + let lineIndex = 0; + const newLineUtf8 = '\n'.charCodeAt(0); + while (true) { + const nextLineAt = beforeTarget.indexOf(newLineUtf8, startOfLineUtf8); + if (nextLineAt < 0) break; + startOfLineUtf8 = nextLineAt + 1; + lineIndex++; + } + const lineUtf16 = document.lineAt(lineIndex); + + // Move forward from a synced position in the text until the + // target pos is found: + let currentUtf8 = startOfLineUtf8; + let currentUtf16 = document.offsetAt(lineUtf16.range.start); + + const decodeBuffer = new Uint8Array(10); + const utf8Encoder = new TextEncoder(); + while (currentUtf8 < posUtf8) { + const { written } = utf8Encoder.encodeInto(text.charAt(currentUtf16), decodeBuffer); + currentUtf8 += written; + currentUtf16++; + } + return currentUtf16; + }; + + type FixedEdit = { + range: vscode.Range, + formatted: string, + }; + + const edits: FixedEdit[] = []; + for (const edit of decoded) { + // Convert from utf8 to utf16: + const range = new vscode.Range( + document.positionAt(utf8ToUtf16Pos(edit.start)), + document.positionAt(utf8ToUtf16Pos(edit.end)) + ); + + if (editor.document.getText(range) !== document.getText(range)) { + // The text that was formatted has changed while we were working. + vscode.window.showWarningMessage(`Dioxus formatting was ignored since the source file changed before the change could be applied.`); + continue; + } + + edits.push({ + range, + formatted: edit.formatted, + }); + } + + // Apply edits: + editor.edit(editBuilder => { + edits.forEach((edit) => editBuilder.replace(edit.range, edit.formatted)); + }, { + undoStopAfter: false, + undoStopBefore: false + }) + } catch (err) { + vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed!\n${err}\n\nData from Dioxus-CLI:\n${originalResult}`); + } + }); + + child_proc.on('error', (err) => { + vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed! \n${err}`); + }); + } catch (error) { + vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed! \n${error}`); } } diff --git a/extension/tsconfig.json b/extension/tsconfig.json index 39ed78e3e..32dda5bc9 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "module": "commonjs", - "target": "es2019", - "lib": ["ES2019"], + "target": "es2021", + "lib": ["ES2021"], "outDir": "out", "sourceMap": true, "strict": true, From bc29cf4d28816fa602edd0dbcebb73281c953713 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Thu, 6 Apr 2023 02:55:53 +0200 Subject: [PATCH 404/895] extension specific config for formatOnSave feature --- extension/package.json | 30 ++++++++++++++++++++++++++++-- extension/src/main.ts | 11 ++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/extension/package.json b/extension/package.json index 3e4ca4b83..11b32ec88 100644 --- a/extension/package.json +++ b/extension/package.json @@ -42,7 +42,33 @@ "command": "extension.formatRsxDocument", "title": "Dioxus: Format RSX Document" } - ] + ], + "configuration": { + "properties": { + "dioxus.formatOnSave": { + "type": [ + "string" + ], + "default": "followFormatOnSave", + "enum": [ + "followFormatOnSave", + "enabled", + "disabled" + ], + "enumItemLabels": [ + "Follow the normal formatOnSave config", + "Enabled", + "Disabled" + ], + "enumDescriptions": [ + "Only format Rsx when saving files if the editor.formatOnSave config is enabled", + "Always format Rsx when a Rust file is saved", + "Never format Rsx when a file is saved" + ], + "description": "Format RSX when a file is saved." + } + } + } }, "scripts": { "vscode:prepublish": "npm run build-base -- --minify", @@ -73,4 +99,4 @@ "dependencies": { "vsce": "^2.9.2" } -} +} \ No newline at end of file diff --git a/extension/src/main.ts b/extension/src/main.ts index 989220456..be3740c7d 100644 --- a/extension/src/main.ts +++ b/extension/src/main.ts @@ -117,11 +117,16 @@ function fmtSelection() { function fmtDocumentOnSave(e: vscode.TextDocumentWillSaveEvent) { // check the settings to make sure format on save is configured - if (!vscode.workspace.getConfiguration('editor', e.document).get('formatOnSave')) { - return; + const dioxusConfig = vscode.workspace.getConfiguration('dioxus', e.document).get('formatOnSave'); + const globalConfig = vscode.workspace.getConfiguration('editor', e.document).get('formatOnSave'); + if ( + (dioxusConfig === 'enabled') || + (dioxusConfig !== 'disabled' && globalConfig) + ) { + fmtDocument(e.document); } - fmtDocument(e.document); } + function fmtDocument(document: vscode.TextDocument) { try { if (document.languageId !== "rust" || document.uri.scheme !== "file") { From 073c4140d9547741f578ed999877ab25cc0c163a Mon Sep 17 00:00:00 2001 From: Andrew Collins <50530928+ProfXwing@users.noreply.github.com> Date: Wed, 5 Apr 2023 22:09:17 -0400 Subject: [PATCH 405/895] added web context back and updated wry to latest --- packages/desktop/Cargo.toml | 2 +- packages/desktop/src/cfg.rs | 5 +++-- packages/desktop/src/lib.rs | 6 ++++-- packages/desktop/src/protocol.rs | 13 ++++++++----- packages/desktop/src/webview.rs | 15 +++++++-------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 7645e4de5..5722a42a2 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -21,7 +21,7 @@ serde = "1.0.136" serde_json = "1.0.79" thiserror = "1.0.30" log = "0.4.14" -wry = { version = "0.23.4" } +wry = { version = "0.27.2" } futures-channel = "0.3.21" tokio = { version = "1.16.1", features = [ "sync", diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 7b37b46d4..d7f1b5dfa 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::PathBuf; use wry::application::window::Icon; @@ -28,7 +29,7 @@ type DropHandler = Box bool>; pub(crate) type WryProtocol = ( String, - Box>) -> WryResult>> + 'static>, + Box>) -> WryResult>> + 'static>, ); impl Config { @@ -98,7 +99,7 @@ impl Config { /// Set a custom protocol pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self where - F: Fn(&HttpRequest>) -> WryResult>> + 'static, + F: Fn(&HttpRequest>) -> WryResult>> + 'static, { self.protocols.push((name, Box::new(handler))); self diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 75c67dd22..434cf3305 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -36,8 +36,8 @@ use tao::{ }; pub use wry; pub use wry::application as tao; -use wry::application::window::WindowId; use wry::webview::WebView; +use wry::{application::window::WindowId, webview::WebContext}; /// Launch the WebView and run the event loop. /// @@ -281,7 +281,7 @@ fn create_new_window( event_handlers: &WindowEventHandlers, shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { - let webview = webview::build(&mut cfg, event_loop, proxy.clone()); + let (webview, web_context) = webview::build(&mut cfg, event_loop, proxy.clone()); dom.base_scope().provide_context(DesktopContext::new( webview.clone(), @@ -299,6 +299,7 @@ fn create_new_window( webview, dom, waker: waker::tao_waker(proxy, id), + web_context, } } @@ -306,6 +307,7 @@ struct WebviewHandler { dom: VirtualDom, webview: Rc, waker: Waker, + web_context: WebContext, } /// Poll the virtualdom until it's pending diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index f8c002a6a..efdc849a5 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,5 +1,8 @@ use dioxus_interpreter_js::INTERPRETER_JS; -use std::path::{Path, PathBuf}; +use std::{ + borrow::Cow, + path::{Path, PathBuf}, +}; use wry::{ http::{status::StatusCode, Request, Response}, Result, @@ -27,7 +30,7 @@ pub(super) fn desktop_handler( custom_head: Option, custom_index: Option, root_name: &str, -) -> Result>> { +) -> 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. @@ -53,7 +56,7 @@ pub(super) fn desktop_handler( return Response::builder() .header("Content-Type", "text/html") - .body(body) + .body(Cow::from(body)) .map_err(From::from); } @@ -72,13 +75,13 @@ pub(super) fn desktop_handler( if asset.exists() { return Response::builder() .header("Content-Type", get_mime_from_path(&asset)?) - .body(std::fs::read(asset)?) + .body(Cow::from(std::fs::read(asset)?)) .map_err(From::from); } Response::builder() .status(StatusCode::NOT_FOUND) - .body(String::from("Not Found").into_bytes()) + .body(Cow::from(String::from("Not Found").into_bytes())) .map_err(From::from) } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 099a2bd94..c6909972f 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -7,13 +7,13 @@ use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use wry; pub use wry::application as tao; use wry::application::window::Window; -use wry::webview::{WebView, WebViewBuilder}; +use wry::webview::{WebContext, WebView, WebViewBuilder}; pub fn build( cfg: &mut Config, event_loop: &EventLoopWindowTarget, proxy: EventLoopProxy, -) -> Rc { +) -> (Rc, WebContext) { let builder = cfg.window.clone(); let window = builder.build(event_loop).unwrap(); let file_handler = cfg.file_drop_handler.take(); @@ -33,6 +33,8 @@ pub fn build( )); } + let mut web_context = WebContext::new(cfg.data_dir.clone()); + let mut webview = WebViewBuilder::new(window) .unwrap() .with_transparent(cfg.window.window.transparent) @@ -52,11 +54,8 @@ pub fn build( .as_ref() .map(|handler| handler(window, evet)) .unwrap_or_default() - }); - - // These are commented out because wry is currently broken in wry - // let mut web_context = WebContext::new(cfg.data_dir.clone()); - // .with_web_context(&mut web_context); + }) + .with_web_context(&mut web_context); for (name, handler) in cfg.protocols.drain(..) { webview = webview.with_custom_protocol(name, handler) @@ -82,5 +81,5 @@ pub fn build( webview = webview.with_devtools(true); } - Rc::new(webview.build().unwrap()) + (Rc::new(webview.build().unwrap()), web_context) } From d1d0ffd912cc533346e7b13b39c45f09ade669ab Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Thu, 6 Apr 2023 05:22:14 +0200 Subject: [PATCH 406/895] fix off-by-one error for utf8 to utf16 pos conversion --- extension/src/main.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/extension/src/main.ts b/extension/src/main.ts index be3740c7d..e9580d3bb 100644 --- a/extension/src/main.ts +++ b/extension/src/main.ts @@ -169,7 +169,7 @@ function fmtDocument(document: vscode.TextDocument) { if (result.length === 0) return; - let decoded: RsxEdit[] = JSON.parse(result); + const decoded: RsxEdit[] = JSON.parse(result); if (decoded.length === 0) return; // Preform edits at the end of the file @@ -182,16 +182,15 @@ function fmtDocument(document: vscode.TextDocument) { const utf8Text = new TextEncoder().encode(text); const utf8ToUtf16Pos = (posUtf8: number) => { - const beforeTarget = utf8Text.slice(0, posUtf8 - 1); - // Find the line of the position as well as the utf8 and // utf16 indexes for the start of that line: let startOfLineUtf8 = 0; let lineIndex = 0; const newLineUtf8 = '\n'.charCodeAt(0); + // eslint-disable-next-line no-constant-condition while (true) { - const nextLineAt = beforeTarget.indexOf(newLineUtf8, startOfLineUtf8); - if (nextLineAt < 0) break; + const nextLineAt = utf8Text.indexOf(newLineUtf8, startOfLineUtf8); + if (nextLineAt < 0 || posUtf8 <= nextLineAt) break; startOfLineUtf8 = nextLineAt + 1; lineIndex++; } @@ -212,6 +211,7 @@ function fmtDocument(document: vscode.TextDocument) { return currentUtf16; }; + type FixedEdit = { range: vscode.Range, formatted: string, @@ -237,13 +237,14 @@ function fmtDocument(document: vscode.TextDocument) { }); } + // Apply edits: editor.edit(editBuilder => { edits.forEach((edit) => editBuilder.replace(edit.range, edit.formatted)); }, { undoStopAfter: false, undoStopBefore: false - }) + }); } catch (err) { vscode.window.showWarningMessage(`Errors occurred while formatting. Make sure you have the most recent Dioxus-CLI installed!\n${err}\n\nData from Dioxus-CLI:\n${originalResult}`); } From f1f7517b888e9e77e612d656ee0c876717c799af Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 6 Apr 2023 11:11:08 -0500 Subject: [PATCH 407/895] Fix form events with select multiple --- packages/html/src/events/form.rs | 2 +- packages/interpreter/src/interpreter.js | 41 +++++++---------- packages/web/src/dom.rs | 59 ++++++++++++------------- 3 files changed, 45 insertions(+), 57 deletions(-) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 361ebe2d4..6edf60448 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -10,7 +10,7 @@ pub type FormEvent = Event; pub struct FormData { pub value: String, - pub values: HashMap, + pub values: HashMap>, #[cfg_attr(feature = "serialize", serde(skip))] pub files: Option>, diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index b921c7c22..653eb15fb 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -17,8 +17,7 @@ class ListenerMap { } else { this.global[event_name].active++; } - } - else { + } else { const id = element.getAttribute("data-dioxus-id"); if (!this.local[id]) { this.local[id] = {}; @@ -32,11 +31,13 @@ class ListenerMap { if (bubbles) { this.global[event_name].active--; if (this.global[event_name].active === 0) { - this.root.removeEventListener(event_name, this.global[event_name].callback); + this.root.removeEventListener( + event_name, + this.global[event_name].callback + ); delete this.global[event_name]; } - } - else { + } else { const id = element.getAttribute("data-dioxus-id"); delete this.local[id][event_name]; if (this.local[id].length === 0) { @@ -143,8 +144,7 @@ class Interpreter { SetAttribute(id, field, value, ns) { if (value === null) { this.RemoveAttribute(id, field, ns); - } - else { + } else { const node = this.nodes[id]; this.SetAttributeInner(node, field, value, ns); } @@ -342,7 +342,6 @@ class Interpreter { this.RemoveEventListener(edit.id, edit.name); break; case "NewEventListener": - let bubbles = event_bubbles(edit.name); // this handler is only provided on desktop implementations since this @@ -360,7 +359,10 @@ class Interpreter { let a_element = target.closest("a"); if (a_element != null) { event.preventDefault(); - if (shouldPreventDefault !== `onclick` && a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`) { + if ( + shouldPreventDefault !== `onclick` && + a_element.getAttribute(`dioxus-prevent-default`) !== `onclick` + ) { const href = a_element.getAttribute("href"); if (href !== "" && href !== null && href !== undefined) { window.ipc.postMessage( @@ -404,23 +406,10 @@ class Interpreter { target.tagName === "FORM" && (event.type === "submit" || event.type === "input") ) { - for (let x = 0; x < target.elements.length; x++) { - let element = target.elements[x]; - let name = element.getAttribute("name"); - if (name != null) { - if (element.getAttribute("type") === "checkbox") { - // @ts-ignore - contents.values[name] = element.checked ? "true" : "false"; - } else if (element.getAttribute("type") === "radio") { - if (element.checked) { - contents.values[name] = element.value; - } - } else { - // @ts-ignore - contents.values[name] = - element.value ?? element.textContent; - } - } + const formData = new FormData(target); + + for (let name of formData.keys()) { + contents.values[name] = formData.getAll(name); } } diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 4d17749d8..5b56e663e 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -13,9 +13,10 @@ use dioxus_core::{ use dioxus_html::{event_bubbles, CompositionData, FormData}; use dioxus_interpreter_js::{save_template, Channel}; use futures_channel::mpsc; +use js_sys::Array; use rustc_hash::FxHashMap; use std::{any::Any, rc::Rc}; -use wasm_bindgen::{closure::Closure, JsCast}; +use wasm_bindgen::{closure::Closure, prelude::wasm_bindgen, JsCast}; use web_sys::{Document, Element, Event, HtmlElement}; use crate::Config; @@ -325,35 +326,16 @@ fn read_input_to_data(target: Element) -> Rc { // try to fill in form values if let Some(form) = target.dyn_ref::() { - let elements = form.elements(); - for x in 0..elements.length() { - let element = elements.item(x).unwrap(); - if let Some(name) = element.get_attribute("name") { - let value: Option = element - .dyn_ref() - .map(|input: &web_sys::HtmlInputElement| { - match input.type_().as_str() { - "checkbox" => { - match input.checked() { - true => Some("true".to_string()), - false => Some("false".to_string()), - } - }, - "radio" => { - match input.checked() { - true => Some(input.value()), - false => None, - } - } - _ => Some(input.value()) - } - }) - .or_else(|| element.dyn_ref().map(|input: &web_sys::HtmlTextAreaElement| Some(input.value()))) - .or_else(|| element.dyn_ref().map(|input: &web_sys::HtmlSelectElement| Some(input.value()))) - .or_else(|| Some(element.dyn_ref::().unwrap().text_content())) - .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener"); - if let Some(value) = value { - values.insert(name, value); + let form_data = get_form_data(form); + for value in form_data.entries().into_iter().flatten() { + if let Ok(array) = value.dyn_into::() { + if let Some(name) = array.get(0).as_string() { + if let Ok(item_values) = array.get(1).dyn_into::() { + let item_values = + item_values.iter().filter_map(|v| v.as_string()).collect(); + + values.insert(name, item_values); + } } } } @@ -366,6 +348,23 @@ fn read_input_to_data(target: Element) -> Rc { }) } +// web-sys does not expose the keys api for form data, so we need to manually bind to it +#[wasm_bindgen(inline_js = r#" + export function get_form_data(form) { + let values = new Map(); + const formData = new FormData(form); + + for (let name of formData.keys()) { + values.set(name, formData.getAll(name)); + } + + return values; + } +"#)] +extern "C" { + fn get_form_data(form: &web_sys::HtmlFormElement) -> js_sys::Map; +} + fn walk_event_for_id(event: &web_sys::Event) -> Option<(ElementId, web_sys::Element)> { let mut target = event .target() From 37dcbbf75877d6e52e5477da7678d757ee9cca6c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 6 Apr 2023 11:29:53 -0500 Subject: [PATCH 408/895] disable browser shortcut keys on windows --- packages/desktop/Cargo.toml | 2 +- packages/desktop/src/cfg.rs | 5 +++-- packages/desktop/src/protocol.rs | 13 ++++++++----- packages/desktop/src/webview.rs | 7 +++++++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 7645e4de5..5722a42a2 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -21,7 +21,7 @@ serde = "1.0.136" serde_json = "1.0.79" thiserror = "1.0.30" log = "0.4.14" -wry = { version = "0.23.4" } +wry = { version = "0.27.2" } futures-channel = "0.3.21" tokio = { version = "1.16.1", features = [ "sync", diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 7b37b46d4..d7f1b5dfa 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::PathBuf; use wry::application::window::Icon; @@ -28,7 +29,7 @@ type DropHandler = Box bool>; pub(crate) type WryProtocol = ( String, - Box>) -> WryResult>> + 'static>, + Box>) -> WryResult>> + 'static>, ); impl Config { @@ -98,7 +99,7 @@ impl Config { /// Set a custom protocol pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self where - F: Fn(&HttpRequest>) -> WryResult>> + 'static, + F: Fn(&HttpRequest>) -> WryResult>> + 'static, { self.protocols.push((name, Box::new(handler))); self diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index f8c002a6a..efdc849a5 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,5 +1,8 @@ use dioxus_interpreter_js::INTERPRETER_JS; -use std::path::{Path, PathBuf}; +use std::{ + borrow::Cow, + path::{Path, PathBuf}, +}; use wry::{ http::{status::StatusCode, Request, Response}, Result, @@ -27,7 +30,7 @@ pub(super) fn desktop_handler( custom_head: Option, custom_index: Option, root_name: &str, -) -> Result>> { +) -> 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. @@ -53,7 +56,7 @@ pub(super) fn desktop_handler( return Response::builder() .header("Content-Type", "text/html") - .body(body) + .body(Cow::from(body)) .map_err(From::from); } @@ -72,13 +75,13 @@ pub(super) fn desktop_handler( if asset.exists() { return Response::builder() .header("Content-Type", get_mime_from_path(&asset)?) - .body(std::fs::read(asset)?) + .body(Cow::from(std::fs::read(asset)?)) .map_err(From::from); } Response::builder() .status(StatusCode::NOT_FOUND) - .body(String::from("Not Found").into_bytes()) + .body(Cow::from(String::from("Not Found").into_bytes())) .map_err(From::from) } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 099a2bd94..4aa24a088 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -54,6 +54,13 @@ pub fn build( .unwrap_or_default() }); + #[cfg(windows)] + { + // Windows has a platform specific settings to disable the browser shortcut keys + use wry::webview::WebViewBuilderExtWindows; + webview = webview.with_browser_accelerator_keys(false); + } + // These are commented out because wry is currently broken in wry // let mut web_context = WebContext::new(cfg.data_dir.clone()); // .with_web_context(&mut web_context); From b2c87f5c47a1cdf5269bd2b2d2518cd263a52161 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 6 Apr 2023 16:59:25 -0500 Subject: [PATCH 409/895] create scafolding for the shadow dom --- packages/native-core/src/custom_element.rs | 134 +++++++++++++++++ packages/native-core/src/dioxus.rs | 1 + packages/native-core/src/lib.rs | 3 + packages/native-core/src/node.rs | 6 + packages/native-core/src/passes.rs | 3 + packages/native-core/src/real_dom.rs | 12 ++ packages/native-core/src/shadow_dom.rs | 26 ++++ packages/native-core/src/utils/mod.rs | 1 - .../native-core/src/utils/widget_watcher.rs | 136 ------------------ packages/native-core/tests/passes.rs | 1 + 10 files changed, 186 insertions(+), 137 deletions(-) create mode 100644 packages/native-core/src/custom_element.rs create mode 100644 packages/native-core/src/shadow_dom.rs delete mode 100644 packages/native-core/src/utils/widget_watcher.rs diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs new file mode 100644 index 000000000..8f6142076 --- /dev/null +++ b/packages/native-core/src/custom_element.rs @@ -0,0 +1,134 @@ +use std::{ + cell::RefCell, + sync::{Arc, RwLock}, +}; + +use rustc_hash::FxHashMap; +use shipyard::Component; + +use crate::{ + node::{FromAnyValue, NodeType}, + node_ref::AttributeMask, + prelude::{NodeImmutable, NodeMut, RealDom}, + real_dom::NodeTypeMut, + shadow_dom::ShadowDom, + NodeId, +}; + +#[derive(Default)] +pub(crate) struct CustomElementRegistry { + builders: FxHashMap<&'static str, CustomElementBuilder>, +} + +impl CustomElementRegistry { + pub fn register>(&mut self) { + self.builders.insert( + W::NAME, + CustomElementBuilder { + create: |dom, light_root_id| Box::new(W::create(dom, light_root_id)), + }, + ); + } + + pub fn add_shadow_dom(&self, mut node: NodeMut) { + let element_tag = if let NodeType::Element(el) = &*node.node_type() { + Some(el.tag.clone()) + } else { + None + }; + if let Some(element_tag) = element_tag { + if let Some(builder) = self.builders.get(element_tag.as_str()) { + let boxed_widget = { + let light_root_id = node.id(); + let dom = node.real_dom_mut(); + (builder.create)(dom, light_root_id) + }; + + let boxed_widget = CustomElementManager { + inner: Arc::new(RwLock::new(boxed_widget)), + }; + + let NodeTypeMut::Element(mut el) = node.node_type_mut()else{ + panic!("The type of the light element should not change when creating a shadow DOM") + }; + + *el.shadow_root_mut() = Some(ShadowDom::new(boxed_widget).into()); + } + } + } +} + +struct CustomElementBuilder { + create: fn(&mut RealDom, NodeId) -> Box>, +} + +/// A controlled element that renders to a shadow DOM +pub trait CustomElement: Send + Sync + 'static { + /// The tag the widget is registered under. + const NAME: &'static str; + + /// Create a new widget without mounting it. + fn create(dom: &mut RealDom, light_root_id: NodeId) -> Self; + + /// The root node of the widget. + fn root(&self) -> NodeId; + + /// Called when the attributes of the widget are changed. + fn attributes_changed(&mut self, _dom: &mut RealDom, _attributes: &AttributeMask); +} + +/// A factory for creating widgets +trait ElementFactory, V: FromAnyValue + Send + Sync = ()>: + Send + Sync + 'static +{ + /// The tag the widget is registered under. + const NAME: &'static str; + + /// Create a new widget. + fn create(dom: &mut RealDom, light_root_id: NodeId) -> W; +} + +impl, V: FromAnyValue + Send + Sync> ElementFactory for W { + const NAME: &'static str = W::NAME; + + fn create(dom: &mut RealDom, light_root_id: NodeId) -> Self { + Self::create(dom, light_root_id) + } +} + +/// A trait for updating widgets +trait CustomElementUpdater: Send + Sync + 'static { + /// Called when the attributes of the widget are changed. + fn attributes_changed(&mut self, _dom: &mut RealDom, _attributes: &AttributeMask); + + /// The root node of the widget. + fn root(&self) -> NodeId; +} + +impl, V: FromAnyValue + Send + Sync> CustomElementUpdater for W { + fn attributes_changed(&mut self, root: &mut RealDom, attributes: &AttributeMask) { + self.attributes_changed(root, attributes); + } + + fn root(&self) -> NodeId { + self.root() + } +} + +pub struct CustomElementManager { + inner: Arc>>>, +} + +impl CustomElementManager { + pub fn root(&self) -> NodeId { + self.inner.read().unwrap().root() + } +} + +impl Clone for CustomElementManager { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs index 3e9ff9ee0..9d50b1224 100644 --- a/packages/native-core/src/dioxus.rs +++ b/packages/native-core/src/dioxus.rs @@ -262,6 +262,7 @@ fn create_template_node( }) .collect(), listeners: FxHashSet::default(), + shadow: None, }); let node_id = rdom.create_node(node).id(); for child in *children { diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index ca8e8e5ee..6dfeb81cd 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -7,6 +7,7 @@ use std::hash::BuildHasherDefault; use node_ref::NodeMask; use rustc_hash::FxHasher; +pub mod custom_element; #[cfg(feature = "dioxus")] pub mod dioxus; pub mod layout_attributes; @@ -15,8 +16,10 @@ pub mod node_ref; pub mod node_watcher; mod passes; pub mod real_dom; +mod shadow_dom; pub mod tree; pub mod utils; + pub use shipyard::EntityId as NodeId; pub mod exports { diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 42ff8229f..2cbfa3fb3 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -7,6 +7,8 @@ use std::{ fmt::{Debug, Display}, }; +use crate::shadow_dom::ShadowDom; + /// A element node in the RealDom #[derive(Debug, Clone, Default)] pub struct ElementNode { @@ -18,6 +20,9 @@ pub struct ElementNode { pub attributes: FxHashMap>, /// The events the element is listening for pub listeners: FxHashSet, + /// The shadow dom of the element + // This is a rare property, so it is stored in an `Box` to save space + pub shadow: Option>>, } impl ElementNode { @@ -28,6 +33,7 @@ impl ElementNode { namespace: namespace.into(), attributes: Default::default(), listeners: Default::default(), + shadow: Default::default(), } } } diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 2a84e6df4..8696b8a89 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -104,6 +104,9 @@ pub trait State: Any + Send + Sync { /// This is a mask of what aspects of the node are required to update this state const NODE_MASK: NodeMaskBuilder<'static>; + /// Does the state traverse into the shadow dom? + const TRAVERSE_SHADOW_DOM: bool = false; + /// Update this state in a node, returns if the state was updated fn update<'a>( &mut self, diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 7d318ddc1..9e6146319 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -17,6 +17,7 @@ use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::{AttributeWatcher, NodeWatcher}; use crate::passes::{DirtyNodeStates, TypeErasedState}; use crate::prelude::AttributeMaskBuilder; +use crate::shadow_dom::ShadowDom; use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView}; use crate::NodeId; use crate::{FxDashSet, SendAnyMap}; @@ -139,6 +140,7 @@ impl RealDom { namespace: Some("Root".to_string()), attributes: FxHashMap::default(), listeners: FxHashSet::default(), + shadow: None, }); let root_id = world.add_entity(root_node); { @@ -1056,6 +1058,16 @@ impl ElementNodeMut<'_, V> { pub fn listeners(&self) -> &FxHashSet { &self.element().listeners } + + /// Get the shadow root of the element + pub fn shadow_root(&self) -> Option<&ShadowDom> { + self.element().shadow.as_deref() + } + + /// Get the shadow root of the element + pub fn shadow_root_mut(&mut self) -> &mut Option>> { + &mut self.element_mut().shadow + } } // Create a workload from all of the passes. This orders the passes so that each pass will only run at most once. diff --git a/packages/native-core/src/shadow_dom.rs b/packages/native-core/src/shadow_dom.rs new file mode 100644 index 000000000..262d6fbb6 --- /dev/null +++ b/packages/native-core/src/shadow_dom.rs @@ -0,0 +1,26 @@ +use std::fmt::Debug; + +use crate::{custom_element::CustomElementManager, node::FromAnyValue, prelude::NodeRef, NodeId}; + +#[derive(Clone)] +pub struct ShadowDom { + shadow_root: NodeId, + updater: CustomElementManager, +} + +impl ShadowDom { + pub fn new(updater: CustomElementManager) -> Self { + Self { + shadow_root: updater.root(), + updater, + } + } +} + +impl Debug for ShadowDom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ShadowDom") + .field("shadow_root", &self.shadow_root) + .finish() + } +} diff --git a/packages/native-core/src/utils/mod.rs b/packages/native-core/src/utils/mod.rs index 95ccc35be..a78b5310b 100644 --- a/packages/native-core/src/utils/mod.rs +++ b/packages/native-core/src/utils/mod.rs @@ -5,4 +5,3 @@ mod persistant_iterator; pub use persistant_iterator::*; pub mod cursor; -pub mod widget_watcher; diff --git a/packages/native-core/src/utils/widget_watcher.rs b/packages/native-core/src/utils/widget_watcher.rs deleted file mode 100644 index c6836697b..000000000 --- a/packages/native-core/src/utils/widget_watcher.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Widget utilities for defining, registering and updating widgets - -use std::sync::{Arc, RwLock}; - -use rustc_hash::FxHashMap; -use shipyard::Component; - -use crate::{ - node::{FromAnyValue, NodeType}, - node_ref::AttributeMask, - node_watcher::{AttributeWatcher, NodeWatcher}, - prelude::{NodeImmutable, NodeMut, RealDom}, - NodeId, -}; - -/// A watcher that handlers registering and updating widgets -#[derive(Default, Clone)] -pub struct WidgetWatcher { - inner: Arc>>, -} - -impl NodeWatcher for WidgetWatcher { - fn on_node_added(&mut self, node: NodeMut) { - let mut inner = self.inner.write().unwrap(); - inner.on_node_added(node); - } - - fn on_node_removed(&mut self, node: NodeMut) { - let mut inner = self.inner.write().unwrap(); - inner.on_node_removed(node); - } -} - -impl WidgetWatcher { - /// Register a widget - pub fn register_widget + 'static, O: WidgetUpdater>(&mut self) { - let mut inner = self.inner.write().unwrap(); - inner.builders.insert( - W::NAME, - WidgetBuilder { - create: |mut node| Box::new(W::create(&mut node)), - }, - ); - } - - /// Attach the widget watcher to the RealDom - pub fn attach(&self, dom: &mut RealDom) { - dom.add_node_watcher(self.clone()); - dom.add_attribute_watcher(self.clone()); - } -} - -impl AttributeWatcher for WidgetWatcher { - fn on_attributes_changed(&self, node: NodeMut, attributes: &AttributeMask) { - let mut inner = self.inner.write().unwrap(); - if let Some(widget) = inner.widgets.get_mut(&node.id()) { - widget.dyn_widget.attributes_changed(node, attributes); - } - } -} - -#[derive(Default)] -struct WidgetWatcherInner { - builders: FxHashMap<&'static str, WidgetBuilder>, - widgets: FxHashMap>, -} - -impl NodeWatcher for WidgetWatcherInner { - fn on_node_added(&mut self, node: NodeMut) { - let node_type = node.node_type(); - if let NodeType::Element(el) = &*node_type { - if let Some(builder) = self.builders.get(el.tag.as_str()) { - drop(node_type); - let id = node.id(); - let widget = (builder.create)(node); - self.widgets.insert(id, BoxedWidget { dyn_widget: widget }); - } - } - } - - fn on_node_removed(&mut self, node: NodeMut) { - self.widgets.remove(&node.id()); - } -} - -#[derive(Component)] -struct BoxedWidget { - dyn_widget: Box>, -} - -struct WidgetBuilder { - create: fn(NodeMut) -> Box>, -} - -/// A controlled element (a.k.a. widget) -pub trait Widget: Send + Sync + 'static { - /// The tag the widget is registered under. - const NAME: &'static str; - - /// Create a new widget. - fn create(root: &mut NodeMut) -> Self; - - /// Called when the attributes of the widget are changed. - fn attributes_changed(&mut self, _root: NodeMut, _attributes: &AttributeMask); -} - -/// A factory for creating widgets -pub trait WidgetFactory, V: FromAnyValue + Send + Sync = ()>: - Send + Sync + 'static -{ - /// The tag the widget is registered under. - const NAME: &'static str; - - /// Create a new widget. - fn create(root: &mut NodeMut) -> W; -} - -impl, V: FromAnyValue + Send + Sync> WidgetFactory for W { - const NAME: &'static str = W::NAME; - - fn create(root: &mut NodeMut) -> Self { - W::create(root) - } -} - -/// A trait for updating widgets -pub trait WidgetUpdater: Send + Sync + 'static { - /// Called when the attributes of the widget are changed. - fn attributes_changed(&mut self, _root: NodeMut, _attributes: &AttributeMask); -} - -impl, V: FromAnyValue + Send + Sync> WidgetUpdater for W { - fn attributes_changed(&mut self, root: NodeMut, attributes: &AttributeMask) { - self.attributes_changed(root, attributes); - } -} diff --git a/packages/native-core/tests/passes.rs b/packages/native-core/tests/passes.rs index 368333fb5..9a0fbe51d 100644 --- a/packages/native-core/tests/passes.rs +++ b/packages/native-core/tests/passes.rs @@ -10,6 +10,7 @@ fn create_blank_element() -> NodeType { namespace: None, attributes: FxHashMap::default(), listeners: FxHashSet::default(), + shadow: None, }) } From fe75138e429fe3db055ca029ba9aad924eeba682 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 7 Apr 2023 09:35:32 -0500 Subject: [PATCH 410/895] fix dangerous_inner_html with SSR --- packages/ssr/src/cache.rs | 16 +++++++++++++++- packages/ssr/src/renderer.rs | 23 +++++++++++++++++++++-- packages/ssr/tests/inner_html.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 packages/ssr/tests/inner_html.rs diff --git a/packages/ssr/src/cache.rs b/packages/ssr/src/cache.rs index e261d3b65..a67fd5f22 100644 --- a/packages/ssr/src/cache.rs +++ b/packages/ssr/src/cache.rs @@ -23,6 +23,8 @@ pub enum Segment { // This will be true if there are static styles inside_style_tag: bool, }, + /// A marker for where to insert a dynamic inner html + InnerHtmlMarker, } impl std::fmt::Write for StringChain { @@ -69,6 +71,9 @@ impl StringCache { write!(chain, "<{tag}")?; // we need to collect the styles and write them at the end let mut styles = Vec::new(); + // we need to collect the inner html and write it at the end + let mut inner_html = None; + // we need to keep track of if we have dynamic attrs to know if we need to insert a style and inner_html marker let mut has_dynamic_attrs = false; for attr in *attrs { match attr { @@ -77,7 +82,9 @@ impl StringCache { value, namespace, } => { - if let Some("style") = namespace { + if *name == "dangerous_inner_html" { + inner_html = Some(value); + } else if let Some("style") = namespace { styles.push((name, value)); } else { write!(chain, " {name}=\"{value}\"")?; @@ -110,6 +117,13 @@ impl StringCache { write!(chain, "/>")?; } else { write!(chain, ">")?; + // Write the static inner html, or insert a marker if dynamic inner html is possible + if let Some(inner_html) = inner_html { + chain.write_str(inner_html)?; + } else if has_dynamic_attrs { + chain.segments.push(Segment::InnerHtmlMarker); + } + for child in *children { Self::recurse(child, cur_path, root_idx, chain)?; } diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index be4025dba..cfa08aee4 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -70,6 +70,8 @@ impl Renderer { .or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap())) .clone(); + let mut inner_html = None; + // We need to keep track of the dynamic styles so we can insert them into the right place let mut accumulated_dynamic_styles = Vec::new(); @@ -77,7 +79,9 @@ impl Renderer { match segment { Segment::Attr(idx) => { let attr = &template.dynamic_attrs[*idx]; - if attr.namespace == Some("style") { + if attr.name == "dangerous_inner_html" { + inner_html = Some(attr); + } else if attr.namespace == Some("style") { accumulated_dynamic_styles.push(attr); } else { match attr.value { @@ -165,6 +169,19 @@ impl Renderer { accumulated_dynamic_styles.clear(); } } + + Segment::InnerHtmlMarker => { + if let Some(inner_html) = inner_html.take() { + let inner_html = &inner_html.value; + match inner_html { + AttributeValue::Text(value) => write!(buf, "{}", value)?, + AttributeValue::Bool(value) => write!(buf, "{}", value)?, + AttributeValue::Float(f) => write!(buf, "{}", f)?, + AttributeValue::Int(i) => write!(buf, "{}", i)?, + _ => {} + } + } + } } } @@ -208,7 +225,9 @@ fn to_string_works() { StyleMarker { inside_style_tag: false, }, - PreRendered(">Hello world 1 -->".into(),), + PreRendered(">".into()), + InnerHtmlMarker, + PreRendered("Hello world 1 -->".into(),), Node(0,), PreRendered( "<-- Hello world 2

nest 1
nest 2
".into(), diff --git a/packages/ssr/tests/inner_html.rs b/packages/ssr/tests/inner_html.rs new file mode 100644 index 000000000..11fb94746 --- /dev/null +++ b/packages/ssr/tests/inner_html.rs @@ -0,0 +1,26 @@ +use dioxus::prelude::*; + +#[test] +fn static_inner_html() { + fn app(cx: Scope) -> Element { + render! { div { dangerous_inner_html: "
1234
" } } + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); +} + +#[test] +fn dynamic_inner_html() { + fn app(cx: Scope) -> Element { + let inner_html = "
1234
"; + render! { div { dangerous_inner_html: "{inner_html}" } } + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); +} From a590a07b3fe92c26ce17ddd5718ed1fbb63f13a1 Mon Sep 17 00:00:00 2001 From: Anatol Ulrich <45840+spookyvision@users.noreply.github.com> Date: Fri, 7 Apr 2023 17:19:31 +0200 Subject: [PATCH 411/895] propagate `features` to `dioxus serve` #122 fixed `--features` for `dioxus build`, this PR adds the same for `dioxus serve` --- src/cli/serve/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index 841e72d10..ce0dd743e 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -30,6 +30,10 @@ impl Serve { if self.serve.profile.is_some() { crate_config.set_profile(self.serve.profile.unwrap()); } + + if self.serve.features.is_some() { + crate_config.set_features(self.serve.features.unwrap()); + } let platform = self.serve.platform.unwrap_or_else(|| { crate_config From 874956bc503cfdba7c0425fb75e360ebce5674f9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 7 Apr 2023 11:11:46 -0500 Subject: [PATCH 412/895] intial implementation of shadow trees --- packages/native-core/src/custom_element.rs | 17 +- packages/native-core/src/passes.rs | 2 +- packages/native-core/src/real_dom.rs | 4 + packages/native-core/src/tree.rs | 213 ++++++++++++++++++--- 4 files changed, 199 insertions(+), 37 deletions(-) diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs index 8f6142076..9b3a19c04 100644 --- a/packages/native-core/src/custom_element.rs +++ b/packages/native-core/src/custom_element.rs @@ -1,10 +1,6 @@ -use std::{ - cell::RefCell, - sync::{Arc, RwLock}, -}; +use std::sync::{Arc, RwLock}; use rustc_hash::FxHashMap; -use shipyard::Component; use crate::{ node::{FromAnyValue, NodeType}, @@ -15,11 +11,18 @@ use crate::{ NodeId, }; -#[derive(Default)] pub(crate) struct CustomElementRegistry { builders: FxHashMap<&'static str, CustomElementBuilder>, } +impl Default for CustomElementRegistry { + fn default() -> Self { + Self { + builders: FxHashMap::default(), + } + } +} + impl CustomElementRegistry { pub fn register>(&mut self) { self.builders.insert( @@ -99,7 +102,7 @@ impl, V: FromAnyValue + Send + Sync> ElementFactory fo /// A trait for updating widgets trait CustomElementUpdater: Send + Sync + 'static { /// Called when the attributes of the widget are changed. - fn attributes_changed(&mut self, _dom: &mut RealDom, _attributes: &AttributeMask); + fn attributes_changed(&mut self, dom: &mut RealDom, attributes: &AttributeMask); /// The root node of the widget. fn root(&self) -> NodeId; diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 8696b8a89..16d0f71fc 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -104,7 +104,7 @@ pub trait State: Any + Send + Sync { /// This is a mask of what aspects of the node are required to update this state const NODE_MASK: NodeMaskBuilder<'static>; - /// Does the state traverse into the shadow dom? + /// Does the state traverse into the shadow dom or pass over it. This should be true for layout and false for styles const TRAVERSE_SHADOW_DOM: bool = false; /// Update this state in a node, returns if the state was updated diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 9e6146319..72d8bce9c 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -10,6 +10,7 @@ use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; +use crate::custom_element::CustomElementRegistry; use crate::node::{ ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, TextNode, }; @@ -112,6 +113,7 @@ pub struct RealDom { attribute_watchers: AttributeWatchers, workload: ScheduledWorkload, root_id: NodeId, + custom_elements: CustomElementRegistry, phantom: std::marker::PhantomData, } @@ -170,6 +172,7 @@ impl RealDom { attribute_watchers: Default::default(), workload, root_id, + custom_elements: Default::default(), phantom: std::marker::PhantomData, } } @@ -759,6 +762,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { } let id = self.id(); self.dom.tree_mut().replace(id, new); + self.remove(); } /// Add an event listener diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index df25deac3..b87b11ab5 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -4,11 +4,25 @@ use crate::NodeId; use shipyard::{Component, EntitiesViewMut, Get, View, ViewMut}; use std::fmt::Debug; +/// A subtree of a tree. +#[derive(PartialEq, Eq, Clone, Debug, Component)] +pub struct Subtree { + /// The root of the subtree + shadow_roots: Vec, + /// The node that children of the super tree should be inserted under. + slot: Option, + /// The node in the super tree that the subtree is attached to. + super_tree_root: NodeId, +} + /// A node in a tree. #[derive(PartialEq, Eq, Clone, Debug, Component)] pub struct Node { parent: Option, children: Vec, + child_subtree: Option, + /// If this node is a slot in a subtree, this is node whose child_subtree is that subtree. + slot_for_supertree: Option, height: u16, } @@ -23,6 +37,8 @@ pub trait TreeRef { fn parent_id(&self, id: NodeId) -> Option; /// The children ids of the node. fn children_ids(&self, id: NodeId) -> Vec; + /// The subtree tree under the node. + fn subtree(&self, id: NodeId) -> Option<&Subtree>; /// The height of the node. fn height(&self, id: NodeId) -> Option; /// Returns true if the node exists. @@ -31,10 +47,8 @@ pub trait TreeRef { /// A mutable view of a tree. pub trait TreeMut: TreeRef { - /// Removes the node and all of its children. + /// Removes the node and its children from the tree but do not delete the entities. fn remove(&mut self, id: NodeId); - /// Removes the node and all of its children. - fn remove_single(&mut self, id: NodeId); /// Adds a new node to the tree. fn create_node(&mut self, id: NodeId); /// Adds a child to the node. @@ -45,6 +59,8 @@ pub trait TreeMut: TreeRef { fn insert_before(&mut self, old_id: NodeId, new_id: NodeId); /// Inserts a node after another node. fn insert_after(&mut self, old_id: NodeId, new_id: NodeId); + /// Creates a new subtree. + fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec, slot: Option); } impl<'a> TreeRef for TreeRefView<'a> { @@ -65,16 +81,39 @@ impl<'a> TreeRef for TreeRefView<'a> { fn contains(&self, id: NodeId) -> bool { self.get(id).is_ok() } + + fn subtree(&self, id: NodeId) -> Option<&Subtree> { + self.get(id).ok()?.child_subtree.as_ref() + } } impl<'a> TreeMut for TreeMutView<'a> { fn remove(&mut self, id: NodeId) { fn recurse(tree: &mut TreeMutView<'_>, id: NodeId) { - let children = tree.children_ids(id); + let (supertree, children) = { + let node = (&mut tree.1).get(id).unwrap(); + (node.slot_for_supertree, std::mem::take(&mut node.children)) + }; + for child in children { recurse(tree, child); } + + // If this node is a slot in a subtree, remove it from the subtree. + if let Some(supertree) = supertree { + let supertree_root = (&mut tree.1).get(supertree).unwrap(); + + if let Some(subtree) = &mut supertree_root.child_subtree { + subtree.slot = None; + } + + debug_assert!( + supertree_root.children.is_empty(), + "Subtree root should have no children when slot is removed." + ); + } } + { let mut node_data_mut = &mut self.1; if let Some(parent) = node_data_mut.get(id).unwrap().parent { @@ -86,16 +125,6 @@ impl<'a> TreeMut for TreeMutView<'a> { recurse(self, id); } - fn remove_single(&mut self, id: NodeId) { - { - let mut node_data_mut = &mut self.1; - if let Some(parent) = node_data_mut.get(id).unwrap().parent { - let parent = (&mut node_data_mut).get(parent).unwrap(); - parent.children.retain(|&child| child != id); - } - } - } - fn create_node(&mut self, id: NodeId) { let (entities, node_data_mut) = self; entities.add_component( @@ -105,19 +134,20 @@ impl<'a> TreeMut for TreeMutView<'a> { parent: None, children: Vec::new(), height: 0, + child_subtree: None, + slot_for_supertree: None, }, ); } fn add_child(&mut self, parent: NodeId, new: NodeId) { - let height; { let mut node_state = &mut self.1; (&mut node_state).get(new).unwrap().parent = Some(parent); let parent = (&mut node_state).get(parent).unwrap(); parent.children.push(new); - height = parent.height + 1; } + let height = child_height((&self.1).get(parent).unwrap(), self); set_height(self, new, height); } @@ -133,27 +163,29 @@ impl<'a> TreeMut for TreeMutView<'a> { break; } } - let height = parent.height + 1; + let height = child_height((&self.1).get(parent_id).unwrap(), self); set_height(self, new_id, height); } } - // remove the old node self.remove(old_id); } fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) { - let mut node_state = &mut self.1; - let old_node = node_state.get(old_id).unwrap(); - let parent_id = old_node.parent.expect("tried to insert before root"); - (&mut node_state).get(new_id).unwrap().parent = Some(parent_id); - let parent = (&mut node_state).get(parent_id).unwrap(); + let parent_id = { + let old_node = self.1.get(old_id).unwrap(); + old_node.parent.expect("tried to insert before root") + }; + { + (&mut self.1).get(new_id).unwrap().parent = Some(parent_id); + } + let parent = (&mut self.1).get(parent_id).unwrap(); let index = parent .children .iter() .position(|child| *child == old_id) .unwrap(); parent.children.insert(index, new_id); - let height = parent.height + 1; + let height = child_height((&self.1).get(parent_id).unwrap(), self); set_height(self, new_id, height); } @@ -169,21 +201,91 @@ impl<'a> TreeMut for TreeMutView<'a> { .position(|child| *child == old_id) .unwrap(); parent.children.insert(index + 1, new_id); - let height = parent.height + 1; + let height = child_height((&self.1).get(parent_id).unwrap(), self); set_height(self, new_id, height); } + + fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec, slot: Option) { + let (_, node_data_mut) = self; + + let light_root_height; + { + let subtree = Subtree { + super_tree_root: id, + shadow_roots: shadow_roots.clone(), + slot, + }; + + let light_root = node_data_mut + .get(id) + .expect("tried to create subtree with non-existent id"); + + light_root.child_subtree = Some(subtree); + light_root_height = light_root.height; + + if let Some(slot) = slot { + let slot = node_data_mut + .get(slot) + .expect("tried to create subtree with non-existent slot"); + slot.slot_for_supertree = Some(id); + } + } + + // Now that we have created the subtree, we need to update the height of the subtree roots + for root in shadow_roots { + set_height(self, root, light_root_height + 1); + } + } +} + +fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 { + match &parent.child_subtree { + Some(subtree) => { + if let Some(slot) = subtree.slot { + tree.height(slot) + .expect("Attempted to read a slot that does not exist") + + 1 + } else { + panic!("Attempted to read the height of a subtree without a slot"); + } + } + None => parent.height + 1, + } } /// Sets the height of a node and updates the height of all its children fn set_height(tree: &mut TreeMutView<'_>, node: NodeId, height: u16) { - let children = { + let (subtree, supertree, children) = { let mut node_data_mut = &mut tree.1; let mut node = (&mut node_data_mut).get(node).unwrap(); node.height = height; - node.children.clone() + + ( + node.child_subtree.clone(), + node.slot_for_supertree, + node.children.clone(), + ) }; - for child in children { - set_height(tree, child, height + 1); + + // If the children are actually part of a subtree, there height is determined by the height of the subtree + if let Some(subtree) = subtree { + // Set the height of the subtree roots + for &shadow_root in &subtree.shadow_roots { + set_height(tree, shadow_root, height); + } + } else { + // Otherwise, we just set the height of the children to be one more than the height of the parent + for child in children { + set_height(tree, child, height + 1); + } + } + + // If this nodes is a slot for a subtree, we need to go to the super tree and update the height of its children + if let Some(supertree) = supertree { + let children = (&tree.1).get(supertree).unwrap().children.clone(); + for child in children { + set_height(tree, child, height + 1); + } } } @@ -209,6 +311,11 @@ impl<'a> TreeRef for TreeMutView<'a> { fn contains(&self, id: NodeId) -> bool { self.1.get(id).is_ok() } + + fn subtree(&self, id: NodeId) -> Option<&Subtree> { + let node_data = &self.1; + node_data.get(id).unwrap().child_subtree.as_ref() + } } #[test] @@ -235,6 +342,54 @@ fn creation() { assert_eq!(tree.children_ids(parent_id), &[child_id]); } +#[test] +fn subtree_creation() { + use shipyard::World; + #[derive(Component)] + struct Num(i32); + + let mut world = World::new(); + // Create main tree + let parent_id = world.add_entity(Num(1i32)); + let child_id = world.add_entity(Num(0i32)); + + // Create shadow tree + let shadow_parent_id = world.add_entity(Num(2i32)); + let shadow_child_id = world.add_entity(Num(3i32)); + + let mut tree = world.borrow::().unwrap(); + + tree.create_node(parent_id); + tree.create_node(child_id); + + tree.add_child(parent_id, child_id); + + tree.create_node(shadow_parent_id); + tree.create_node(shadow_child_id); + + tree.add_child(shadow_parent_id, shadow_child_id); + + assert_eq!(tree.height(parent_id), Some(0)); + assert_eq!(tree.height(child_id), Some(1)); + assert_eq!(tree.parent_id(parent_id), None); + assert_eq!(tree.parent_id(child_id).unwrap(), parent_id); + assert_eq!(tree.children_ids(parent_id), &[child_id]); + + assert_eq!(tree.height(shadow_parent_id), Some(0)); + assert_eq!(tree.height(shadow_child_id), Some(1)); + assert_eq!(tree.parent_id(shadow_parent_id), None); + assert_eq!(tree.parent_id(shadow_child_id).unwrap(), shadow_parent_id); + assert_eq!(tree.children_ids(shadow_parent_id), &[shadow_child_id]); + + // Add shadow tree to main tree + tree.create_subtree(parent_id, vec![shadow_parent_id], Some(shadow_child_id)); + + assert_eq!(tree.height(parent_id), Some(0)); + assert_eq!(tree.height(shadow_parent_id), Some(1)); + assert_eq!(tree.height(shadow_child_id), Some(2)); + assert_eq!(tree.height(child_id), Some(3)); +} + #[test] fn insertion() { use shipyard::World; From 32945998c33a593c5ad46abc40d2cc69a3af2648 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 7 Apr 2023 11:23:37 -0500 Subject: [PATCH 413/895] implement removing subtrees --- packages/native-core/src/tree.rs | 65 +++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index b87b11ab5..e44970649 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -61,6 +61,8 @@ pub trait TreeMut: TreeRef { fn insert_after(&mut self, old_id: NodeId, new_id: NodeId); /// Creates a new subtree. fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec, slot: Option); + /// Remove any subtree. + fn remove_subtree(&mut self, id: NodeId); } impl<'a> TreeRef for TreeRefView<'a> { @@ -236,6 +238,36 @@ impl<'a> TreeMut for TreeMutView<'a> { set_height(self, root, light_root_height + 1); } } + + fn remove_subtree(&mut self, id: NodeId) { + let (_, node_data_mut) = self; + + if let Ok(node) = node_data_mut.get(id) { + if let Some(subtree) = node.child_subtree.take() { + // Remove the slot's link to the subtree + if let Some(slot) = subtree.slot { + let slot = node_data_mut + .get(slot) + .expect("tried to remove subtree with non-existent slot"); + slot.slot_for_supertree = None; + } + + let node = node_data_mut.get(id).unwrap(); + + // Reset the height of the light root's children + let height = node.height; + for child in node.children.clone() { + println!("child: {:?}", child); + set_height(self, child, height + 1); + } + + // Reset the height of the shadow roots + for root in &subtree.shadow_roots { + set_height(self, *root, 0); + } + } + } + } } fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 { @@ -343,7 +375,7 @@ fn creation() { } #[test] -fn subtree_creation() { +fn subtree() { use shipyard::World; #[derive(Component)] struct Num(i32); @@ -369,6 +401,7 @@ fn subtree_creation() { tree.add_child(shadow_parent_id, shadow_child_id); + // Check that both trees are correct individually assert_eq!(tree.height(parent_id), Some(0)); assert_eq!(tree.height(child_id), Some(1)); assert_eq!(tree.parent_id(parent_id), None); @@ -388,6 +421,36 @@ fn subtree_creation() { assert_eq!(tree.height(shadow_parent_id), Some(1)); assert_eq!(tree.height(shadow_child_id), Some(2)); assert_eq!(tree.height(child_id), Some(3)); + assert_eq!( + tree.1 + .get(parent_id) + .unwrap() + .child_subtree + .as_ref() + .unwrap() + .shadow_roots, + &[shadow_parent_id] + ); + assert_eq!( + tree.1.get(shadow_child_id).unwrap().slot_for_supertree, + Some(parent_id) + ); + + // Remove shadow tree from main tree + tree.remove_subtree(parent_id); + + // Check that both trees are correct individually + assert_eq!(tree.height(parent_id), Some(0)); + assert_eq!(tree.height(child_id), Some(1)); + assert_eq!(tree.parent_id(parent_id), None); + assert_eq!(tree.parent_id(child_id).unwrap(), parent_id); + assert_eq!(tree.children_ids(parent_id), &[child_id]); + + assert_eq!(tree.height(shadow_parent_id), Some(0)); + assert_eq!(tree.height(shadow_child_id), Some(1)); + assert_eq!(tree.parent_id(shadow_parent_id), None); + assert_eq!(tree.parent_id(shadow_child_id).unwrap(), shadow_parent_id); + assert_eq!(tree.children_ids(shadow_parent_id), &[shadow_child_id]); } #[test] From a5c46b0e5ce6acd2594f93bde35a5c486f35a828 Mon Sep 17 00:00:00 2001 From: Andrew Collins <50530928+ProfXwing@users.noreply.github.com> Date: Sat, 8 Apr 2023 11:23:48 -0400 Subject: [PATCH 414/895] new window returns desktop context --- packages/desktop/src/desktop_context.rs | 9 +++----- packages/desktop/src/lib.rs | 30 +++++++++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 2ed4bbee9..03166d272 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,6 +1,5 @@ use std::cell::RefCell; use std::rc::Rc; -use std::rc::Weak; use crate::create_new_window; use crate::eval::EvalResult; @@ -112,8 +111,8 @@ impl DesktopContext { /// You can use this to control other windows from the current window. /// /// Be careful to not create a cycle of windows, or you might leak memory. - pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> Weak { - let window = create_new_window( + pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> DesktopContext { + let (window, desktop_context) = create_new_window( cfg, &self.event_loop, &self.proxy, @@ -133,11 +132,9 @@ impl DesktopContext { .send_event(UserWindowEvent(EventData::Poll, id)) .unwrap(); - let webview = window.webview.clone(); - self.pending_windows.borrow_mut().push(window); - Rc::downgrade(&webview) + desktop_context } /// trigger the drag-window event diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 75c67dd22..0a9a8558c 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -144,8 +144,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) let shortcut_manager = ShortcutRegistry::new(&event_loop); - // By default, we'll create a new window when the app starts - queue.borrow_mut().push(create_new_window( + let (web_view, _) = create_new_window( cfg, &event_loop, &proxy, @@ -153,7 +152,10 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) &queue, &event_handlers, shortcut_manager.clone(), - )); + ); + + // By default, we'll create a new window when the app starts + queue.borrow_mut().push(web_view); event_loop.run(move |window_event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; @@ -280,26 +282,30 @@ fn create_new_window( queue: &WebviewQueue, event_handlers: &WindowEventHandlers, shortcut_manager: ShortcutRegistry, -) -> WebviewHandler { +) -> (WebviewHandler, DesktopContext) { let webview = webview::build(&mut cfg, event_loop, proxy.clone()); - - dom.base_scope().provide_context(DesktopContext::new( + let desktop_context = DesktopContext::new( webview.clone(), proxy.clone(), event_loop.clone(), queue.clone(), event_handlers.clone(), shortcut_manager, - )); + ); + + dom.base_scope().provide_context(desktop_context.clone()); let id = webview.window().id(); // We want to poll the virtualdom and the event loop at the same time, so the waker will be connected to both - WebviewHandler { - webview, - dom, - waker: waker::tao_waker(proxy, id), - } + ( + WebviewHandler { + webview, + dom, + waker: waker::tao_waker(proxy, id), + }, + desktop_context, + ) } struct WebviewHandler { From 60be849ff0185a7351ec46d7f17f49074913522d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 8 Apr 2023 18:53:53 -0500 Subject: [PATCH 415/895] handle passes entering or avoiding the shadow tree --- packages/native-core-macro/src/lib.rs | 2 +- packages/native-core/src/custom_element.rs | 43 ++++--- packages/native-core/src/dioxus.rs | 1 - packages/native-core/src/lib.rs | 1 - packages/native-core/src/node.rs | 6 - packages/native-core/src/passes.rs | 48 +++++++- packages/native-core/src/real_dom.rs | 42 ++++--- packages/native-core/src/shadow_dom.rs | 26 ----- packages/native-core/src/tree.rs | 130 ++++++++++++--------- packages/native-core/tests/passes.rs | 1 - 10 files changed, 167 insertions(+), 133 deletions(-) delete mode 100644 packages/native-core/src/shadow_dom.rs diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index fd25c3868..7960a0d4c 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -336,7 +336,7 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { let (#(#split_views,)*) = data; let tree = run_view.tree.clone(); let node_types = run_view.node_type.clone(); - dioxus_native_core::prelude::run_pass(type_id, dependants.clone(), pass_direction, run_view, |id, context| { + dioxus_native_core::prelude::run_pass(type_id, dependants.clone(), pass_direction, run_view, Self::TRAVERSE_SHADOW_DOM, |id, context| { let node_data: &NodeType<_> = node_types.get(id).unwrap_or_else(|err| panic!("Failed to get node type {:?}", err)); // get all of the states from the tree view // Safety: No node has itself as a parent or child. diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs index 9b3a19c04..f829d89f0 100644 --- a/packages/native-core/src/custom_element.rs +++ b/packages/native-core/src/custom_element.rs @@ -1,13 +1,12 @@ use std::sync::{Arc, RwLock}; use rustc_hash::FxHashMap; +use shipyard::Component; use crate::{ node::{FromAnyValue, NodeType}, node_ref::AttributeMask, prelude::{NodeImmutable, NodeMut, RealDom}, - real_dom::NodeTypeMut, - shadow_dom::ShadowDom, NodeId, }; @@ -28,7 +27,7 @@ impl CustomElementRegistry { self.builders.insert( W::NAME, CustomElementBuilder { - create: |dom, light_root_id| Box::new(W::create(dom, light_root_id)), + create: |dom| Box::new(W::create(dom)), }, ); } @@ -42,27 +41,22 @@ impl CustomElementRegistry { if let Some(element_tag) = element_tag { if let Some(builder) = self.builders.get(element_tag.as_str()) { let boxed_widget = { - let light_root_id = node.id(); let dom = node.real_dom_mut(); - (builder.create)(dom, light_root_id) + (builder.create)(dom) }; let boxed_widget = CustomElementManager { inner: Arc::new(RwLock::new(boxed_widget)), }; - let NodeTypeMut::Element(mut el) = node.node_type_mut()else{ - panic!("The type of the light element should not change when creating a shadow DOM") - }; - - *el.shadow_root_mut() = Some(ShadowDom::new(boxed_widget).into()); + node.insert(boxed_widget); } } } } struct CustomElementBuilder { - create: fn(&mut RealDom, NodeId) -> Box>, + create: fn(&mut RealDom) -> Box>, } /// A controlled element that renders to a shadow DOM @@ -71,11 +65,16 @@ pub trait CustomElement: Send + Sync + 'stat const NAME: &'static str; /// Create a new widget without mounting it. - fn create(dom: &mut RealDom, light_root_id: NodeId) -> Self; + fn create(dom: &mut RealDom) -> Self; - /// The root node of the widget. + /// The root node of the widget. This must be static once the element is created. fn root(&self) -> NodeId; + /// The slot to render children of the element into. This must be static once the element is created. + fn slot(&self) -> Option { + None + } + /// Called when the attributes of the widget are changed. fn attributes_changed(&mut self, _dom: &mut RealDom, _attributes: &AttributeMask); } @@ -88,14 +87,14 @@ trait ElementFactory, V: FromAnyValue + Send + Sync = const NAME: &'static str; /// Create a new widget. - fn create(dom: &mut RealDom, light_root_id: NodeId) -> W; + fn create(dom: &mut RealDom) -> W; } impl, V: FromAnyValue + Send + Sync> ElementFactory for W { const NAME: &'static str = W::NAME; - fn create(dom: &mut RealDom, light_root_id: NodeId) -> Self { - Self::create(dom, light_root_id) + fn create(dom: &mut RealDom) -> Self { + Self::create(dom) } } @@ -118,6 +117,7 @@ impl, V: FromAnyValue + Send + Sync> CustomElementUpdater } } +#[derive(Component, Clone)] pub struct CustomElementManager { inner: Arc>>>, } @@ -126,12 +126,11 @@ impl CustomElementManager { pub fn root(&self) -> NodeId { self.inner.read().unwrap().root() } -} -impl Clone for CustomElementManager { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } + pub fn on_attributes_changed(&self, dom: &mut RealDom, attributes: &AttributeMask) { + self.inner + .write() + .unwrap() + .attributes_changed(dom, attributes); } } diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs index 9d50b1224..3e9ff9ee0 100644 --- a/packages/native-core/src/dioxus.rs +++ b/packages/native-core/src/dioxus.rs @@ -262,7 +262,6 @@ fn create_template_node( }) .collect(), listeners: FxHashSet::default(), - shadow: None, }); let node_id = rdom.create_node(node).id(); for child in *children { diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index 6dfeb81cd..fcbbdd9fb 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -16,7 +16,6 @@ pub mod node_ref; pub mod node_watcher; mod passes; pub mod real_dom; -mod shadow_dom; pub mod tree; pub mod utils; diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 2cbfa3fb3..42ff8229f 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -7,8 +7,6 @@ use std::{ fmt::{Debug, Display}, }; -use crate::shadow_dom::ShadowDom; - /// A element node in the RealDom #[derive(Debug, Clone, Default)] pub struct ElementNode { @@ -20,9 +18,6 @@ pub struct ElementNode { pub attributes: FxHashMap>, /// The events the element is listening for pub listeners: FxHashSet, - /// The shadow dom of the element - // This is a rare property, so it is stored in an `Box` to save space - pub shadow: Option>>, } impl ElementNode { @@ -33,7 +28,6 @@ impl ElementNode { namespace: namespace.into(), attributes: Default::default(), listeners: Default::default(), - shadow: Default::default(), } } } diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 16d0f71fc..f8aa94fa5 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -194,6 +194,7 @@ pub fn run_pass( dependants: FxHashSet, pass_direction: PassDirection, view: RunPassView, + enter_shadow_dom: bool, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool, ) { let RunPassView { @@ -209,9 +210,32 @@ pub fn run_pass( while let Some((height, id)) = dirty.pop_front(type_id) { if (update_node)(id, ctx) { nodes_updated.insert(id); - for id in tree.children_ids(id) { - for dependant in &dependants { - dirty.insert(*dependant, id, height + 1); + let shadow_tree = tree.shadow_tree(id); + match (enter_shadow_dom, shadow_tree) { + (true, Some(shadow_tree)) => { + // If this pass uses the shadow dom, update the shadow dom children instead of the normal children + for id in &shadow_tree.shadow_roots { + for dependant in &dependants { + dirty.insert(*dependant, *id, height + 1); + } + } + } + _ => { + for id in tree.children_ids(id) { + for dependant in &dependants { + dirty.insert(*dependant, id, height + 1); + } + } + } + } + // If this pass uses the shadow dom, update the light dom's children if this node is a slot + if enter_shadow_dom { + if let Some(slot_for_light_tree) = tree.slot_for_light_tree(id) { + for id in tree.children_ids(slot_for_light_tree) { + for dependant in &dependants { + dirty.insert(*dependant, id, height + 1); + } + } } } } @@ -221,9 +245,21 @@ pub fn run_pass( while let Some((height, id)) = dirty.pop_back(type_id) { if (update_node)(id, ctx) { nodes_updated.insert(id); - if let Some(id) = tree.parent_id(id) { - for dependant in &dependants { - dirty.insert(*dependant, id, height - 1); + + // If this pass uses the shadow dom, update the light dom root if this node is a root + let light_tree_root = tree.light_tree_root(id); + match (enter_shadow_dom, light_tree_root) { + (true, Some(light_tree_root)) => { + for dependant in &dependants { + dirty.insert(*dependant, light_tree_root, height + 1); + } + } + _ => { + if let Some(id) = tree.parent_id(id) { + for dependant in &dependants { + dirty.insert(*dependant, id, height - 1); + } + } } } } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 72d8bce9c..9b8ae1983 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; -use crate::custom_element::CustomElementRegistry; +use crate::custom_element::{CustomElementManager, CustomElementRegistry}; use crate::node::{ ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, TextNode, }; @@ -18,7 +18,6 @@ use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::{AttributeWatcher, NodeWatcher}; use crate::passes::{DirtyNodeStates, TypeErasedState}; use crate::prelude::AttributeMaskBuilder; -use crate::shadow_dom::ShadowDom; use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView}; use crate::NodeId; use crate::{FxDashSet, SendAnyMap}; @@ -113,7 +112,7 @@ pub struct RealDom { attribute_watchers: AttributeWatchers, workload: ScheduledWorkload, root_id: NodeId, - custom_elements: CustomElementRegistry, + custom_elements: Arc>>, phantom: std::marker::PhantomData, } @@ -142,7 +141,6 @@ impl RealDom { namespace: Some("Root".to_string()), attributes: FxHashMap::default(), listeners: FxHashSet::default(), - shadow: None, }); let root_id = world.add_entity(root_node); { @@ -189,7 +187,10 @@ impl RealDom { /// Create a new node of the given type in the dom and return a mutable reference to it. pub fn create_node(&mut self, node: impl Into>) -> NodeMut<'_, V> { - let id = self.world.add_entity(node.into()); + let node = node.into(); + let is_element = matches!(node, NodeType::Element(_)); + + let id = self.world.add_entity(node); self.tree_mut().create_node(id); self.dirty_nodes @@ -201,6 +202,15 @@ impl RealDom { .mark_dirty(id, NodeMaskBuilder::ALL.build()); self.dirty_nodes.nodes_created.insert(id); + // Create a custom element if needed + if is_element { + let custom_elements = self.custom_elements.clone(); + custom_elements + .write() + .unwrap() + .add_shadow_dom(NodeMut::new(id, self)); + } + NodeMut::new(id, self) } @@ -280,10 +290,9 @@ impl RealDom { let passes = std::mem::take(&mut self.dirty_nodes.passes_updated); let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated); - // call attribute watchers for (node_id, mask) in &nodes_updated { if self.contains(*node_id) { - // ignore watchers if they are already being modified + // call attribute watchers but ignore watchers if they are already being modified let watchers = self.attribute_watchers.clone(); if let Ok(mut watchers) = watchers.try_write() { for watcher in &mut *watchers { @@ -293,6 +302,15 @@ impl RealDom { ); } }; + + // call custom element watchers + let custom_element_manager = { + let node = self.get_mut(*node_id).unwrap(); + node.get::>().map(|x| x.clone()) + }; + if let Some(custom_element_manager) = custom_element_manager { + custom_element_manager.on_attributes_changed(self, mask.attributes()); + } } } @@ -1062,16 +1080,6 @@ impl ElementNodeMut<'_, V> { pub fn listeners(&self) -> &FxHashSet { &self.element().listeners } - - /// Get the shadow root of the element - pub fn shadow_root(&self) -> Option<&ShadowDom> { - self.element().shadow.as_deref() - } - - /// Get the shadow root of the element - pub fn shadow_root_mut(&mut self) -> &mut Option>> { - &mut self.element_mut().shadow - } } // Create a workload from all of the passes. This orders the passes so that each pass will only run at most once. diff --git a/packages/native-core/src/shadow_dom.rs b/packages/native-core/src/shadow_dom.rs deleted file mode 100644 index 262d6fbb6..000000000 --- a/packages/native-core/src/shadow_dom.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::fmt::Debug; - -use crate::{custom_element::CustomElementManager, node::FromAnyValue, prelude::NodeRef, NodeId}; - -#[derive(Clone)] -pub struct ShadowDom { - shadow_root: NodeId, - updater: CustomElementManager, -} - -impl ShadowDom { - pub fn new(updater: CustomElementManager) -> Self { - Self { - shadow_root: updater.root(), - updater, - } - } -} - -impl Debug for ShadowDom { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ShadowDom") - .field("shadow_root", &self.shadow_root) - .finish() - } -} diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index e44970649..e0b32f28d 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -4,15 +4,15 @@ use crate::NodeId; use shipyard::{Component, EntitiesViewMut, Get, View, ViewMut}; use std::fmt::Debug; -/// A subtree of a tree. +/// A shadow_tree of a tree. #[derive(PartialEq, Eq, Clone, Debug, Component)] -pub struct Subtree { - /// The root of the subtree - shadow_roots: Vec, +pub struct ShadowTree { + /// The root of the shadow_tree + pub shadow_roots: Vec, /// The node that children of the super tree should be inserted under. - slot: Option, - /// The node in the super tree that the subtree is attached to. - super_tree_root: NodeId, + pub slot: Option, + /// The node in the super tree that the shadow_tree is attached to. + pub super_tree_root: NodeId, } /// A node in a tree. @@ -20,9 +20,11 @@ pub struct Subtree { pub struct Node { parent: Option, children: Vec, - child_subtree: Option, - /// If this node is a slot in a subtree, this is node whose child_subtree is that subtree. - slot_for_supertree: Option, + child_subtree: Option, + /// If this node is a slot in a shadow_tree, this is node whose child_subtree is that shadow_tree. + slot_for_light_tree: Option, + /// If this node is a root of a shadow_tree, this is the node whose child_subtree is that shadow_tree. + light_tree_root: Option, height: u16, } @@ -37,8 +39,13 @@ pub trait TreeRef { fn parent_id(&self, id: NodeId) -> Option; /// The children ids of the node. fn children_ids(&self, id: NodeId) -> Vec; - /// The subtree tree under the node. - fn subtree(&self, id: NodeId) -> Option<&Subtree>; + /// The shadow tree tree under the node. + fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree>; + // TODO: rethink naming + /// The node that contains the shadow tree this node is a slot for + fn slot_for_light_tree(&self, id: NodeId) -> Option; + /// The node that contains the shadow tree this node is a root of + fn light_tree_root(&self, id: NodeId) -> Option; /// The height of the node. fn height(&self, id: NodeId) -> Option; /// Returns true if the node exists. @@ -59,9 +66,9 @@ pub trait TreeMut: TreeRef { fn insert_before(&mut self, old_id: NodeId, new_id: NodeId); /// Inserts a node after another node. fn insert_after(&mut self, old_id: NodeId, new_id: NodeId); - /// Creates a new subtree. + /// Creates a new shadow tree. fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec, slot: Option); - /// Remove any subtree. + /// Remove any shadow tree. fn remove_subtree(&mut self, id: NodeId); } @@ -84,34 +91,42 @@ impl<'a> TreeRef for TreeRefView<'a> { self.get(id).is_ok() } - fn subtree(&self, id: NodeId) -> Option<&Subtree> { + fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree> { self.get(id).ok()?.child_subtree.as_ref() } + + fn slot_for_light_tree(&self, id: NodeId) -> Option { + self.get(id).ok()?.slot_for_light_tree + } + + fn light_tree_root(&self, id: NodeId) -> Option { + self.get(id).ok()?.light_tree_root + } } impl<'a> TreeMut for TreeMutView<'a> { fn remove(&mut self, id: NodeId) { fn recurse(tree: &mut TreeMutView<'_>, id: NodeId) { - let (supertree, children) = { + let (light_tree, children) = { let node = (&mut tree.1).get(id).unwrap(); - (node.slot_for_supertree, std::mem::take(&mut node.children)) + (node.slot_for_light_tree, std::mem::take(&mut node.children)) }; for child in children { recurse(tree, child); } - // If this node is a slot in a subtree, remove it from the subtree. - if let Some(supertree) = supertree { - let supertree_root = (&mut tree.1).get(supertree).unwrap(); + // If this node is a slot in a shadow_tree, remove it from the shadow_tree. + if let Some(light_tree) = light_tree { + let light_tree_root = (&mut tree.1).get(light_tree).unwrap(); - if let Some(subtree) = &mut supertree_root.child_subtree { - subtree.slot = None; + if let Some(shadow_tree) = &mut light_tree_root.child_subtree { + shadow_tree.slot = None; } debug_assert!( - supertree_root.children.is_empty(), - "Subtree root should have no children when slot is removed." + light_tree_root.children.is_empty(), + "ShadowTree root should have no children when slot is removed." ); } } @@ -137,7 +152,8 @@ impl<'a> TreeMut for TreeMutView<'a> { children: Vec::new(), height: 0, child_subtree: None, - slot_for_supertree: None, + slot_for_light_tree: None, + light_tree_root: None, }, ); } @@ -212,7 +228,7 @@ impl<'a> TreeMut for TreeMutView<'a> { let light_root_height; { - let subtree = Subtree { + let shadow_tree = ShadowTree { super_tree_root: id, shadow_roots: shadow_roots.clone(), slot, @@ -220,20 +236,20 @@ impl<'a> TreeMut for TreeMutView<'a> { let light_root = node_data_mut .get(id) - .expect("tried to create subtree with non-existent id"); + .expect("tried to create shadow_tree with non-existent id"); - light_root.child_subtree = Some(subtree); + light_root.child_subtree = Some(shadow_tree); light_root_height = light_root.height; if let Some(slot) = slot { let slot = node_data_mut .get(slot) - .expect("tried to create subtree with non-existent slot"); - slot.slot_for_supertree = Some(id); + .expect("tried to create shadow_tree with non-existent slot"); + slot.slot_for_light_tree = Some(id); } } - // Now that we have created the subtree, we need to update the height of the subtree roots + // Now that we have created the shadow_tree, we need to update the height of the shadow_tree roots for root in shadow_roots { set_height(self, root, light_root_height + 1); } @@ -243,13 +259,13 @@ impl<'a> TreeMut for TreeMutView<'a> { let (_, node_data_mut) = self; if let Ok(node) = node_data_mut.get(id) { - if let Some(subtree) = node.child_subtree.take() { - // Remove the slot's link to the subtree - if let Some(slot) = subtree.slot { + if let Some(shadow_tree) = node.child_subtree.take() { + // Remove the slot's link to the shadow_tree + if let Some(slot) = shadow_tree.slot { let slot = node_data_mut .get(slot) - .expect("tried to remove subtree with non-existent slot"); - slot.slot_for_supertree = None; + .expect("tried to remove shadow_tree with non-existent slot"); + slot.slot_for_light_tree = None; } let node = node_data_mut.get(id).unwrap(); @@ -262,7 +278,7 @@ impl<'a> TreeMut for TreeMutView<'a> { } // Reset the height of the shadow roots - for root in &subtree.shadow_roots { + for root in &shadow_tree.shadow_roots { set_height(self, *root, 0); } } @@ -272,13 +288,13 @@ impl<'a> TreeMut for TreeMutView<'a> { fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 { match &parent.child_subtree { - Some(subtree) => { - if let Some(slot) = subtree.slot { + Some(shadow_tree) => { + if let Some(slot) = shadow_tree.slot { tree.height(slot) .expect("Attempted to read a slot that does not exist") + 1 } else { - panic!("Attempted to read the height of a subtree without a slot"); + panic!("Attempted to read the height of a shadow_tree without a slot"); } } None => parent.height + 1, @@ -287,22 +303,22 @@ fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 { /// Sets the height of a node and updates the height of all its children fn set_height(tree: &mut TreeMutView<'_>, node: NodeId, height: u16) { - let (subtree, supertree, children) = { + let (shadow_tree, light_tree, children) = { let mut node_data_mut = &mut tree.1; let mut node = (&mut node_data_mut).get(node).unwrap(); node.height = height; ( node.child_subtree.clone(), - node.slot_for_supertree, + node.slot_for_light_tree, node.children.clone(), ) }; - // If the children are actually part of a subtree, there height is determined by the height of the subtree - if let Some(subtree) = subtree { - // Set the height of the subtree roots - for &shadow_root in &subtree.shadow_roots { + // If the children are actually part of a shadow_tree, there height is determined by the height of the shadow_tree + if let Some(shadow_tree) = shadow_tree { + // Set the height of the shadow_tree roots + for &shadow_root in &shadow_tree.shadow_roots { set_height(tree, shadow_root, height); } } else { @@ -312,9 +328,9 @@ fn set_height(tree: &mut TreeMutView<'_>, node: NodeId, height: u16) { } } - // If this nodes is a slot for a subtree, we need to go to the super tree and update the height of its children - if let Some(supertree) = supertree { - let children = (&tree.1).get(supertree).unwrap().children.clone(); + // If this nodes is a slot for a shadow_tree, we need to go to the super tree and update the height of its children + if let Some(light_tree) = light_tree { + let children = (&tree.1).get(light_tree).unwrap().children.clone(); for child in children { set_height(tree, child, height + 1); } @@ -344,10 +360,20 @@ impl<'a> TreeRef for TreeMutView<'a> { self.1.get(id).is_ok() } - fn subtree(&self, id: NodeId) -> Option<&Subtree> { + fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree> { let node_data = &self.1; node_data.get(id).unwrap().child_subtree.as_ref() } + + fn slot_for_light_tree(&self, id: NodeId) -> Option { + let node_data = &self.1; + node_data.get(id).unwrap().slot_for_light_tree + } + + fn light_tree_root(&self, id: NodeId) -> Option { + let node_data = &self.1; + node_data.get(id).unwrap().light_tree_root + } } #[test] @@ -375,7 +401,7 @@ fn creation() { } #[test] -fn subtree() { +fn shadow_tree() { use shipyard::World; #[derive(Component)] struct Num(i32); @@ -432,7 +458,7 @@ fn subtree() { &[shadow_parent_id] ); assert_eq!( - tree.1.get(shadow_child_id).unwrap().slot_for_supertree, + tree.1.get(shadow_child_id).unwrap().slot_for_light_tree, Some(parent_id) ); diff --git a/packages/native-core/tests/passes.rs b/packages/native-core/tests/passes.rs index 9a0fbe51d..368333fb5 100644 --- a/packages/native-core/tests/passes.rs +++ b/packages/native-core/tests/passes.rs @@ -10,7 +10,6 @@ fn create_blank_element() -> NodeType { namespace: None, attributes: FxHashMap::default(), listeners: FxHashSet::default(), - shadow: None, }) } From 500a73abae25fb9749c30d2c4a29507fde453890 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 8 Apr 2023 19:01:48 -0500 Subject: [PATCH 416/895] allow registering custom element and fix deadlock --- packages/native-core/src/real_dom.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 9b8ae1983..490e04dc6 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; -use crate::custom_element::{CustomElementManager, CustomElementRegistry}; +use crate::custom_element::{CustomElement, CustomElementManager, CustomElementRegistry}; use crate::node::{ ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, TextNode, }; @@ -206,7 +206,7 @@ impl RealDom { if is_element { let custom_elements = self.custom_elements.clone(); custom_elements - .write() + .read() .unwrap() .add_shadow_dom(NodeMut::new(id, self)); } @@ -426,6 +426,11 @@ impl RealDom { pub fn raw_world_mut(&mut self) -> &mut World { &mut self.world } + + /// Registers a new custom element. + pub fn register_custom_element>(&mut self) { + self.custom_elements.write().unwrap().register::() + } } /// A reference to a tracked component in a node. From 05caa475b1d15bf8dd7e9a6dce357cbd1c1ff31b Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 9 Apr 2023 22:54:18 +0800 Subject: [PATCH 417/895] Add timeout count example --- packages/web/Cargo.toml | 2 ++ packages/web/examples/README.md | 10 +++++++++ packages/web/examples/timeout_count.rs | 31 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 packages/web/examples/README.md create mode 100644 packages/web/examples/timeout_count.rs diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 7adfbf13a..12184644c 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -89,3 +89,5 @@ wasm-bindgen-test = "0.3.29" dioxus-ssr = { path = "../ssr", version = "0.3.0"} wasm-logger = "0.2.0" dioxus-web = { path = ".", features = ["hydrate"] } +gloo-timers = "0.2.3" +gloo-dialogs = "0.1.1" diff --git a/packages/web/examples/README.md b/packages/web/examples/README.md new file mode 100644 index 000000000..faa322df3 --- /dev/null +++ b/packages/web/examples/README.md @@ -0,0 +1,10 @@ +Examples +======== + +# Hydrate + +- `hydrate` show hydrate + +# Async + +- `timeout_count` button to add count and show count in the future diff --git a/packages/web/examples/timeout_count.rs b/packages/web/examples/timeout_count.rs new file mode 100644 index 000000000..742e6a49e --- /dev/null +++ b/packages/web/examples/timeout_count.rs @@ -0,0 +1,31 @@ +// https://jakelazaroff.com/words/were-react-hooks-a-mistake/ +use dioxus::prelude::*; + +fn main() { + dioxus_web::launch(app); +} + +fn app(cx: Scope) -> Element { + let count = use_ref(cx, || 0); + let started = use_state(cx, || false); + + let start = move || { + if !*started.get() { + let count = count.clone(); // clone reference rather than value + let alert = move || gloo_dialogs::alert(&format!("Your score was {}!", count.read())); + gloo_timers::callback::Timeout::new(5_000, alert).forget(); + } + started.set(true); // this cannot be done inside condition or infinite loop + }; + + cx.render(rsx! { + button { + onclick: move |_event| { + start(); + *count.write() += 1; + }, + // format is needed as {count} does not seemed to work in `if` within content + if **started { format!("Current score: {}", count.write()) } else { "Start".to_string() } + } + }) +} From 9571adea3068bee5f62e2229004cb873e8dcabaa Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 9 Apr 2023 13:42:40 -0700 Subject: [PATCH 418/895] add counter example --- examples/counter.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 examples/counter.rs diff --git a/examples/counter.rs b/examples/counter.rs new file mode 100644 index 000000000..f51083a95 --- /dev/null +++ b/examples/counter.rs @@ -0,0 +1,36 @@ +//! Comparison example with leptos' counter example +//! https://github.com/leptos-rs/leptos/blob/main/examples/counters/src/lib.rs + +use dioxus::prelude::*; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let counters = use_state(cx, || vec![0, 0, 0]); + let sum: usize = counters.iter().copied().sum(); + + render! { + div { + button { onclick: move |_| counters.make_mut().push(0), "Add counter" } + button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" } + p { "Total: {sum}" } + for (i, counter) in counters.iter().enumerate() { + li { + button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" } + input { + value: "{counter}", + oninput: move |e| { + if let Ok(value) = e.value.parse::() { + counters.make_mut()[i] = value; + } + } + } + button { onclick: move |_| counters.make_mut()[i] += 1, "+1" } + button { onclick: move |_| { counters.make_mut().remove(i); }, "x" } + } + } + } + } +} From d005f3481fda98e50bb107d1cd699c2bd88e23a9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 10 Apr 2023 09:45:16 -0500 Subject: [PATCH 419/895] fix non-bubbling event propagation --- packages/core/src/virtual_dom.rs | 96 ++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 2269815aa..da5526b32 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -384,51 +384,73 @@ impl VirtualDom { data, }; - // Loop through each dynamic attribute in this template before moving up to the template's parent. - while let Some(el_ref) = parent_path { - // safety: we maintain references of all vnodes in the element slab - let template = unsafe { el_ref.template.unwrap().as_ref() }; - let node_template = template.template.get(); - let target_path = el_ref.path; + // If the event bubbles, we traverse through the tree until we find the target element. + if bubbles { + // Loop through each dynamic attribute (in a depth first order) in this template before moving up to the template's parent. + while let Some(el_ref) = parent_path { + // safety: we maintain references of all vnodes in the element slab + let template = unsafe { el_ref.template.unwrap().as_ref() }; + let node_template = template.template.get(); + let target_path = el_ref.path; - for (idx, attr) in template.dynamic_attrs.iter().enumerate() { - let this_path = node_template.attr_paths[idx]; + for (idx, attr) in template.dynamic_attrs.iter().enumerate() { + let this_path = node_template.attr_paths[idx]; - // Remove the "on" prefix if it exists, TODO, we should remove this and settle on one - if attr.name.trim_start_matches("on") == name - && target_path.is_decendant(&this_path) - { - listeners.push(&attr.value); + // Remove the "on" prefix if it exists, TODO, we should remove this and settle on one + if attr.name.trim_start_matches("on") == name + && target_path.is_decendant(&this_path) + { + listeners.push(&attr.value); - // Break if the event doesn't bubble anyways - if !bubbles { - break; + // Break if this is the exact target element. + // This means we won't call two listeners with the same name on the same element. This should be + // documented, or be rejected from the rsx! macro outright + if target_path == this_path { + break; + } } + } - // Break if this is the exact target element. - // This means we won't call two listeners with the same name on the same element. This should be - // documented, or be rejected from the rsx! macro outright - if target_path == this_path { - break; + // Now that we've accumulated all the parent attributes for the target element, call them in reverse order + // We check the bubble state between each call to see if the event has been stopped from bubbling + for listener in listeners.drain(..).rev() { + if let AttributeValue::Listener(listener) = listener { + if let Some(cb) = listener.borrow_mut().as_deref_mut() { + cb(uievent.clone()); + } + + if !uievent.propagates.get() { + return; + } + } + } + + parent_path = template.parent.and_then(|id| self.elements.get(id.0)); + } + } else { + // Otherwise, we just call the listener on the target element + if let Some(el_ref) = parent_path { + // safety: we maintain references of all vnodes in the element slab + let template = unsafe { el_ref.template.unwrap().as_ref() }; + let node_template = template.template.get(); + let target_path = el_ref.path; + + for (idx, attr) in template.dynamic_attrs.iter().enumerate() { + let this_path = node_template.attr_paths[idx]; + + // Remove the "on" prefix if it exists, TODO, we should remove this and settle on one + // Only call the listener if this is the exact target element. + if attr.name.trim_start_matches("on") == name && target_path == this_path { + if let AttributeValue::Listener(listener) = &attr.value { + if let Some(cb) = listener.borrow_mut().as_deref_mut() { + cb(uievent.clone()); + } + + break; + } } } } - - // Now that we've accumulated all the parent attributes for the target element, call them in reverse order - // We check the bubble state between each call to see if the event has been stopped from bubbling - for listener in listeners.drain(..).rev() { - if let AttributeValue::Listener(listener) = listener { - if let Some(cb) = listener.borrow_mut().as_deref_mut() { - cb(uievent.clone()); - } - - if !uievent.propagates.get() { - return; - } - } - } - - parent_path = template.parent.and_then(|id| self.elements.get(id.0)); } } From d29514968f68771e3e6970833cc490fd66c2025b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 10 Apr 2023 11:12:54 -0500 Subject: [PATCH 420/895] fix native core dependancies in a different direction than the pass direction --- packages/native-core-macro/src/lib.rs | 2 +- packages/native-core/examples/font_size.rs | 175 +++++++++++++++++++++ packages/native-core/src/lib.rs | 2 +- packages/native-core/src/passes.rs | 92 +++++++---- packages/native-core/src/real_dom.rs | 57 +++++-- 5 files changed, 282 insertions(+), 46 deletions(-) create mode 100644 packages/native-core/examples/font_size.rs diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index fd25c3868..2c8cef835 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -325,7 +325,7 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { #(#items)* - fn workload_system(type_id: std::any::TypeId, dependants: dioxus_native_core::exports::FxHashSet, pass_direction: dioxus_native_core::prelude::PassDirection) -> dioxus_native_core::exports::shipyard::WorkloadSystem { + fn workload_system(type_id: std::any::TypeId, dependants: std::sync::Arc, pass_direction: dioxus_native_core::prelude::PassDirection) -> dioxus_native_core::exports::shipyard::WorkloadSystem { use dioxus_native_core::exports::shipyard::{IntoWorkloadSystem, Get, AddComponent}; use dioxus_native_core::tree::TreeRef; use dioxus_native_core::prelude::{NodeType, NodeView}; diff --git a/packages/native-core/examples/font_size.rs b/packages/native-core/examples/font_size.rs new file mode 100644 index 000000000..937db0c17 --- /dev/null +++ b/packages/native-core/examples/font_size.rs @@ -0,0 +1,175 @@ +use dioxus_native_core::exports::shipyard::Component; +use dioxus_native_core::node_ref::*; +use dioxus_native_core::prelude::*; +use dioxus_native_core::real_dom::NodeTypeMut; +use dioxus_native_core_macro::partial_derive_state; + +// All states need to derive Component +#[derive(Default, Debug, Copy, Clone, Component)] +struct Size(f64, f64); + +/// Derive some of the boilerplate for the State implementation +#[partial_derive_state] +impl State for Size { + type ParentDependencies = (); + + // The size of the current node depends on the size of its children + type ChildDependencies = (Self,); + + type NodeDependencies = (FontSize,); + + // Size only cares about the width, height, and text parts of the current node + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() + // Get access to the width and height attributes + .with_attrs(AttributeMaskBuilder::Some(&["width", "height"])) + // Get access to the text of the node + .with_text(); + + fn update<'a>( + &mut self, + node_view: NodeView<()>, + (font_size,): ::ElementBorrowed<'a>, + _parent: Option<::ElementBorrowed<'a>>, + children: Vec<::ElementBorrowed<'a>>, + _: &SendAnyMap, + ) -> bool { + let font_size = font_size.size; + let mut width; + let mut height; + if let Some(text) = node_view.text() { + // if the node has text, use the text to size our object + width = text.len() as f64 * font_size; + height = font_size; + } else { + // otherwise, the size is the maximum size of the children + width = children + .iter() + .map(|(item,)| item.0) + .reduce(|accum, item| if accum >= item { accum } else { item }) + .unwrap_or(0.0); + + height = children + .iter() + .map(|(item,)| item.1) + .reduce(|accum, item| if accum >= item { accum } else { item }) + .unwrap_or(0.0); + } + // if the node contains a width or height attribute it overrides the other size + for a in node_view.attributes().into_iter().flatten() { + match &*a.attribute.name { + "width" => width = a.value.as_float().unwrap(), + "height" => height = a.value.as_float().unwrap(), + // because Size only depends on the width and height, no other attributes will be passed to the member + _ => panic!(), + } + } + // to determine what other parts of the dom need to be updated we return a boolean that marks if this member changed + let changed = (width != self.0) || (height != self.1); + *self = Self(width, height); + changed + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Component)] +struct FontSize { + size: f64, +} + +impl Default for FontSize { + fn default() -> Self { + Self { size: 16.0 } + } +} + +#[partial_derive_state] +impl State for FontSize { + // TextColor depends on the TextColor part of the parent + type ParentDependencies = (Self,); + + type ChildDependencies = (); + + type NodeDependencies = (); + + // TextColor only cares about the color attribute of the current node + const NODE_MASK: NodeMaskBuilder<'static> = + // Get access to the color attribute + NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["font-size"])); + + fn update<'a>( + &mut self, + node_view: NodeView<()>, + _node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _children: Vec<::ElementBorrowed<'a>>, + _context: &SendAnyMap, + ) -> bool { + let mut new = None; + for attr in node_view.attributes().into_iter().flatten() { + if attr.attribute.name == "font-size" { + new = Some(FontSize { + size: attr.value.as_float().unwrap(), + }); + } + } + let new = new.unwrap_or(parent.map(|(p,)| *p).unwrap_or_default()); + // check if the member has changed + let changed = new != *self; + *self = new; + changed + } +} + +fn main() -> Result<(), Box> { + let mut rdom: RealDom = RealDom::new([FontSize::to_type_erased(), Size::to_type_erased()]); + + let mut count = 0; + + // intial render + let text_id = rdom.create_node(format!("Count: {count}")).id(); + let mut root = rdom.get_mut(rdom.root_id()).unwrap(); + // set the color to red + if let NodeTypeMut::Element(mut element) = root.node_type_mut() { + element.set_attribute(("color", "style"), "red".to_string()); + element.set_attribute(("font-size", "style"), 1.); + } + root.add_child(text_id); + + let ctx = SendAnyMap::new(); + // update the State for nodes in the real_dom tree + let _to_rerender = rdom.update_state(ctx); + + // we need to run the vdom in a async runtime + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()? + .block_on(async { + loop { + // update the count and font size + count += 1; + let mut text = rdom.get_mut(text_id).unwrap(); + if let NodeTypeMut::Text(mut text) = text.node_type_mut() { + *text = format!("Count: {count}"); + } + if let NodeTypeMut::Element(mut element) = + rdom.get_mut(rdom.root_id()).unwrap().node_type_mut() + { + element.set_attribute(("font-size", "style"), count as f64); + } + + let ctx = SendAnyMap::new(); + let _to_rerender = rdom.update_state(ctx); + + // render... + rdom.traverse_depth_first(|node| { + let indent = " ".repeat(node.height() as usize); + let font_size = *node.get::().unwrap(); + let size = *node.get::().unwrap(); + let id = node.id(); + println!("{indent}{id:?} {font_size:?} {size:?}"); + }); + + // wait 1 second + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + } + }) +} diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index ca8e8e5ee..0740d881a 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -35,7 +35,7 @@ pub mod prelude { pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode}; pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView}; pub use crate::passes::{run_pass, PassDirection, RunPassView, TypeErasedState}; - pub use crate::passes::{Dependancy, DependancyView, State}; + pub use crate::passes::{Dependancy, DependancyView, Dependants, State}; pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom}; pub use crate::NodeId; pub use crate::SendAnyMap; diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 2a84e6df4..b453e32dd 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -126,7 +126,7 @@ pub trait State: Any + Send + Sync { /// Create a workload system for this state fn workload_system( type_id: TypeId, - dependants: FxHashSet, + dependants: Arc, pass_direction: PassDirection, ) -> WorkloadSystem; @@ -138,10 +138,16 @@ pub trait State: Any + Send + Sync { let node_mask = Self::NODE_MASK.build(); TypeErasedState { this_type_id: TypeId::of::(), - combined_dependancy_type_ids: all_dependanices::().iter().copied().collect(), - parent_dependant: !Self::ParentDependencies::type_ids().is_empty(), - child_dependant: !Self::ChildDependencies::type_ids().is_empty(), - dependants: FxHashSet::default(), + parent_dependancies_ids: Self::ParentDependencies::type_ids() + .iter() + .copied() + .collect(), + child_dependancies_ids: Self::ChildDependencies::type_ids() + .iter() + .copied() + .collect(), + node_dependancies_ids: Self::NodeDependencies::type_ids().iter().copied().collect(), + dependants: Default::default(), mask: node_mask, pass_direction: pass_direction::(), workload: Self::workload_system, @@ -166,13 +172,6 @@ fn pass_direction>() -> PassDirection } } -fn all_dependanices>() -> Box<[TypeId]> { - let mut dependencies = S::ParentDependencies::type_ids().to_vec(); - dependencies.extend(S::ChildDependencies::type_ids().iter()); - dependencies.extend(S::NodeDependencies::type_ids().iter()); - dependencies.into_boxed_slice() -} - #[doc(hidden)] #[derive(Borrow, BorrowInfo)] pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> { @@ -188,7 +187,7 @@ pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> { #[doc(hidden)] pub fn run_pass( type_id: TypeId, - dependants: FxHashSet, + dependants: Arc, pass_direction: PassDirection, view: RunPassView, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool, @@ -206,11 +205,7 @@ pub fn run_pass( while let Some((height, id)) = dirty.pop_front(type_id) { if (update_node)(id, ctx) { nodes_updated.insert(id); - for id in tree.children_ids(id) { - for dependant in &dependants { - dirty.insert(*dependant, id, height + 1); - } - } + dependants.mark_dirty(&dirty, id, &tree, height); } } } @@ -218,11 +213,7 @@ pub fn run_pass( while let Some((height, id)) = dirty.pop_back(type_id) { if (update_node)(id, ctx) { nodes_updated.insert(id); - if let Some(id) = tree.parent_id(id) { - for dependant in &dependants { - dirty.insert(*dependant, id, height - 1); - } - } + dependants.mark_dirty(&dirty, id, &tree, height); } } } @@ -230,24 +221,53 @@ pub fn run_pass( while let Some((height, id)) = dirty.pop_back(type_id) { if (update_node)(id, ctx) { nodes_updated.insert(id); - for dependant in &dependants { - dirty.insert(*dependant, id, height); - } + dependants.mark_dirty(&dirty, id, &tree, height); } } } } } +/// The states that depend on this state +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct Dependants { + /// The states in the parent direction that should be invalidated when this state is invalidated + pub parent: Vec, + /// The states in the child direction that should be invalidated when this state is invalidated + pub child: Vec, + /// The states in the node direction that should be invalidated when this state is invalidated + pub node: Vec, +} + +impl Dependants { + fn mark_dirty(&self, dirty: &DirtyNodeStates, id: NodeId, tree: &impl TreeRef, height: u16) { + for dependant in &self.child { + for id in tree.children_ids(id) { + dirty.insert(*dependant, id, height + 1); + } + } + + for dependant in &self.parent { + if let Some(id) = tree.parent_id(id) { + dirty.insert(*dependant, id, height - 1); + } + } + + for dependant in &self.node { + dirty.insert(*dependant, id, height); + } + } +} + /// A type erased version of [`State`] that can be added to the [`crate::prelude::RealDom`] with [`crate::prelude::RealDom::new`] pub struct TypeErasedState { pub(crate) this_type_id: TypeId, - pub(crate) parent_dependant: bool, - pub(crate) child_dependant: bool, - pub(crate) combined_dependancy_type_ids: FxHashSet, - pub(crate) dependants: FxHashSet, + pub(crate) parent_dependancies_ids: FxHashSet, + pub(crate) child_dependancies_ids: FxHashSet, + pub(crate) node_dependancies_ids: FxHashSet, + pub(crate) dependants: Arc, pub(crate) mask: NodeMask, - pub(crate) workload: fn(TypeId, FxHashSet, PassDirection) -> WorkloadSystem, + pub(crate) workload: fn(TypeId, Arc, PassDirection) -> WorkloadSystem, pub(crate) pass_direction: PassDirection, phantom: PhantomData, } @@ -260,10 +280,18 @@ impl TypeErasedState { self.pass_direction, ) } + + pub(crate) fn combined_dependancy_type_ids(&self) -> impl Iterator + '_ { + self.parent_dependancies_ids + .iter() + .chain(self.child_dependancies_ids.iter()) + .chain(self.node_dependancies_ids.iter()) + .copied() + } } /// The direction that a pass should be run in -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum PassDirection { /// The pass should be run from the root to the leaves ParentToChild, diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 25d1ed9fe..c344b9041 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -15,7 +15,7 @@ use crate::node::{ }; use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::NodeWatcher; -use crate::passes::{DirtyNodeStates, TypeErasedState}; +use crate::passes::{DirtyNodeStates, PassDirection, TypeErasedState}; use crate::prelude::AttributeMaskBuilder; use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView}; use crate::NodeId; @@ -68,12 +68,13 @@ impl NodesDirty { } } - /// Mark a node as added or removed from the tree + /// Mark a node that has had a parent changed fn mark_parent_added_or_removed(&mut self, node_id: NodeId) { let hm = self.passes_updated.entry(node_id).or_default(); for pass in &*self.passes { - if pass.parent_dependant { - hm.insert(pass.this_type_id); + // If any of the states in this node depend on the parent then mark them as dirty + for &pass in &pass.parent_dependancies_ids { + hm.insert(pass); } } } @@ -82,8 +83,9 @@ impl NodesDirty { fn mark_child_changed(&mut self, node_id: NodeId) { let hm = self.passes_updated.entry(node_id).or_default(); for pass in &*self.passes { - if pass.child_dependant { - hm.insert(pass.this_type_id); + // If any of the states in this node depend on the children then mark them as dirty + for &pass in &pass.child_dependancies_ids { + hm.insert(pass); } } } @@ -116,16 +118,46 @@ impl RealDom { pub fn new(tracked_states: impl Into]>>) -> RealDom { let mut tracked_states = tracked_states.into(); // resolve dependants for each pass - for i in 1..tracked_states.len() { + for i in 1..=tracked_states.len() { let (before, after) = tracked_states.split_at_mut(i); let (current, before) = before.split_last_mut().unwrap(); - for pass in before.iter_mut().chain(after.iter_mut()) { + for state in before.iter_mut().chain(after.iter_mut()) { + let dependants = Arc::get_mut(&mut state.dependants).unwrap(); + // If this node depends on the other state as a parent, then the other state should update its children of the current type when it is invalidated if current - .combined_dependancy_type_ids - .contains(&pass.this_type_id) + .parent_dependancies_ids + .contains(&state.this_type_id) + && !dependants.child.contains(¤t.this_type_id) { - pass.dependants.insert(current.this_type_id); + dependants.child.push(current.this_type_id); } + // If this node depends on the other state as a child, then the other state should update its parent of the current type when it is invalidated + if current.child_dependancies_ids.contains(&state.this_type_id) + && !dependants.parent.contains(¤t.this_type_id) + { + dependants.parent.push(current.this_type_id); + } + // If this node depends on the other state as a sibling, then the other state should update its siblings of the current type when it is invalidated + if current.node_dependancies_ids.contains(&state.this_type_id) + && !dependants.node.contains(¤t.this_type_id) + { + dependants.node.push(current.this_type_id); + } + } + // If the current state depends on itself, then it should update itself when it is invalidated + let dependants = Arc::get_mut(&mut current.dependants).unwrap(); + match current.pass_direction { + PassDirection::ChildToParent => { + if !dependants.parent.contains(¤t.this_type_id) { + dependants.parent.push(current.this_type_id); + } + } + PassDirection::ParentToChild => { + if !dependants.child.contains(¤t.this_type_id) { + dependants.child.push(current.this_type_id); + } + } + _ => {} } } let workload = construct_workload(&mut tracked_states); @@ -1011,7 +1043,8 @@ fn construct_workload( // mark any dependancies for i in 0..unresloved_workloads.len() { let (_, pass, _) = &unresloved_workloads[i]; - for ty_id in pass.combined_dependancy_type_ids.clone() { + let all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect(); + for ty_id in all_dependancies { let &(dependancy_id, _, _) = unresloved_workloads .iter() .find(|(_, pass, _)| pass.this_type_id == ty_id) From 0e1f015b78e82e28e4a1889eaa6552c6ef981ee1 Mon Sep 17 00:00:00 2001 From: Andrew Collins <50530928+ProfXwing@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:03:46 -0400 Subject: [PATCH 421/895] turn desktop context into Rc --- packages/desktop/src/desktop_context.rs | 19 +++++++++++++------ packages/desktop/src/lib.rs | 22 ++++++++++------------ packages/desktop/src/shortcut.rs | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 03166d272..35da2eab3 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; +use std::rc::Weak; use crate::create_new_window; use crate::eval::EvalResult; @@ -30,8 +31,8 @@ use wry::webview::WebView; pub type ProxyType = EventLoopProxy; /// Get an imperative handle to the current window -pub fn use_window(cx: &ScopeState) -> &DesktopContext { - cx.use_hook(|| cx.consume_context::()) +pub fn use_window(cx: &ScopeState) -> &Rc { + cx.use_hook(|| cx.consume_context::>()) .as_ref() .unwrap() } @@ -111,8 +112,8 @@ impl DesktopContext { /// You can use this to control other windows from the current window. /// /// Be careful to not create a cycle of windows, or you might leak memory. - pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> DesktopContext { - let (window, desktop_context) = create_new_window( + pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> Weak { + let window = create_new_window( cfg, &self.event_loop, &self.proxy, @@ -122,6 +123,12 @@ impl DesktopContext { self.shortcut_manager.clone(), ); + let desktop_context = window + .dom + .base_scope() + .consume_context::>() + .unwrap(); + let id = window.webview.window().id(); self.proxy @@ -134,7 +141,7 @@ impl DesktopContext { self.pending_windows.borrow_mut().push(window); - desktop_context + Rc::downgrade(&desktop_context) } /// trigger the drag-window event @@ -420,7 +427,7 @@ pub fn use_wry_event_handler( let id = desktop.create_wry_event_handler(handler); WryEventHandler { - handlers: desktop.event_handlers, + handlers: desktop.event_handlers.clone(), id, } }) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 0a9a8558c..2a6f5aa6b 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -144,7 +144,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) let shortcut_manager = ShortcutRegistry::new(&event_loop); - let (web_view, _) = create_new_window( + let web_view = create_new_window( cfg, &event_loop, &proxy, @@ -282,30 +282,28 @@ fn create_new_window( queue: &WebviewQueue, event_handlers: &WindowEventHandlers, shortcut_manager: ShortcutRegistry, -) -> (WebviewHandler, DesktopContext) { +) -> WebviewHandler { let webview = webview::build(&mut cfg, event_loop, proxy.clone()); - let desktop_context = DesktopContext::new( + let desktop_context = Rc::from(DesktopContext::new( webview.clone(), proxy.clone(), event_loop.clone(), queue.clone(), event_handlers.clone(), shortcut_manager, - ); + )); dom.base_scope().provide_context(desktop_context.clone()); let id = webview.window().id(); // We want to poll the virtualdom and the event loop at the same time, so the waker will be connected to both - ( - WebviewHandler { - webview, - dom, - waker: waker::tao_waker(proxy, id), - }, - desktop_context, - ) + + WebviewHandler { + webview, + dom, + waker: waker::tao_waker(proxy, id), + } } struct WebviewHandler { diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs index 5232bdb8b..e70d13235 100644 --- a/packages/desktop/src/shortcut.rs +++ b/packages/desktop/src/shortcut.rs @@ -146,7 +146,7 @@ pub struct ShortcutId { /// A global shortcut. This will be automatically removed when it is dropped. pub struct ShortcutHandle { - desktop: DesktopContext, + desktop: Rc, /// The id of the shortcut pub shortcut_id: ShortcutId, } From 64575eaee24fec9d10545648aa7d74f1c766de53 Mon Sep 17 00:00:00 2001 From: Andrew Collins <50530928+ProfXwing@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:06:16 -0400 Subject: [PATCH 422/895] forgot one --- packages/desktop/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 2a6f5aa6b..270eb1580 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -248,7 +248,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) webviews[&event.1] .dom .base_scope() - .consume_context::() + .consume_context::>() .unwrap() .eval .send(msg.params()) From 4a9ebe78d7d41ae79a551e3a9a560bba22894e25 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 11 Apr 2023 11:22:36 -0500 Subject: [PATCH 423/895] fix Linux CI dependancies --- .github/workflows/main.yml | 6 +++--- docs/guide/src/en/getting_started/desktop.md | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 96649c903..a3bff9fc6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,7 +39,7 @@ jobs: override: true - uses: Swatinem/rust-cache@v2 - run: sudo apt-get update - - run: sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev + - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev - uses: actions/checkout@v3 - uses: actions-rs/cargo@v1 with: @@ -58,7 +58,7 @@ jobs: override: true - uses: Swatinem/rust-cache@v2 - run: sudo apt-get update - - run: sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev + - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev - uses: davidB/rust-cargo-make@v1 - uses: browser-actions/setup-firefox@latest - uses: jetli/wasm-pack-action@v0.4.0 @@ -98,7 +98,7 @@ jobs: override: true - uses: Swatinem/rust-cache@v2 - run: sudo apt-get update - - run: sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev + - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev - run: rustup component add clippy - uses: actions/checkout@v3 - uses: actions-rs/cargo@v1 diff --git a/docs/guide/src/en/getting_started/desktop.md b/docs/guide/src/en/getting_started/desktop.md index 311ad2c9f..b24215218 100644 --- a/docs/guide/src/en/getting_started/desktop.md +++ b/docs/guide/src/en/getting_started/desktop.md @@ -5,6 +5,7 @@ Build a standalone native desktop app that looks and feels the same across opera Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory. Examples: + - [File Explorer](https://github.com/DioxusLabs/example-projects/blob/master/file-explorer) - [WiFi Scanner](https://github.com/DioxusLabs/example-projects/blob/master/wifi-scanner) @@ -12,21 +13,22 @@ Examples: ## Support -The desktop is a powerful target for Dioxus but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are *not* available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs *are* accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom web renderer-based DOM renderer with WGPU integrations. +The desktop is a powerful target for Dioxus but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are _not_ available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs _are_ accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom web renderer-based DOM renderer with WGPU integrations. Dioxus Desktop is built off [Tauri](https://tauri.app/). Right now there aren't any Dioxus abstractions over the menubar, handling, etc, so you'll want to leverage Tauri – mostly [Wry](http://github.com/tauri-apps/wry/) and [Tao](http://github.com/tauri-apps/tao)) directly. # Getting started ## Platform-Specific Dependencies + Dioxus desktop renders through a web view. Depending on your platform, you might need to install some dependancies. ### Windows -Windows Desktop apps depend on WebView2 – a library that should be installed in all modern Windows distributions. If you have Edge installed, then Dioxus will work fine. If you *don't* have Webview2, [then you can install it through Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). MS provides 3 options: +Windows Desktop apps depend on WebView2 – a library that should be installed in all modern Windows distributions. If you have Edge installed, then Dioxus will work fine. If you _don't_ have Webview2, [then you can install it through Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). MS provides 3 options: -1. A tiny "evergreen" *bootstrapper* that fetches an installer from Microsoft's CDN -2. A tiny *installer* that fetches Webview2 from Microsoft's CDN +1. A tiny "evergreen" _bootstrapper_ that fetches an installer from Microsoft's CDN +2. A tiny _installer_ that fetches Webview2 from Microsoft's CDN 3. A statically linked version of Webview2 in your final binary for offline users For development purposes, use Option 1. @@ -36,19 +38,18 @@ For development purposes, use Option 1. Webview Linux apps require WebkitGtk. When distributing, this can be part of your dependency tree in your `.rpm` or `.deb`. However, likely, your users will already have WebkitGtk. ```bash -sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libappindicator3-dev +sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev ``` When using Debian/bullseye `libappindicator3-dev` is no longer available but replaced by `libayatana-appindicator3-dev`. ```bash # on Debian/bullseye use: -sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev +sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev ``` If you run into issues, make sure you have all the basics installed, as outlined in the [Tauri docs](https://tauri.studio/v1/guides/getting-started/prerequisites#setting-up-linux). - ### MacOS Currently – everything for macOS is built right in! However, you might run into an issue if you're using nightly Rust due to some permissions issues in our Tao dependency (which have been resolved but not published). From 6653d4861421158a6c28121bea240864e7af6f0b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 11 Apr 2023 11:34:33 -0500 Subject: [PATCH 424/895] fix clippy lint in desktop --- packages/desktop/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 434cf3305..cdb592f72 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -307,6 +307,8 @@ struct WebviewHandler { dom: VirtualDom, webview: Rc, waker: Waker, + // This is nessisary because of a bug in wry. Wry assumes the webcontext is alive for the lifetime of the webview. We need to keep the webcontext alive, otherwise the webview will crash + #[allow(dead_code)] web_context: WebContext, } From 00174d4f461ac3ae003e741a25f5ffe4c087a790 Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Tue, 11 Apr 2023 19:58:07 +0200 Subject: [PATCH 425/895] switch router to `async-lock` --- packages/router-core/Cargo.toml | 2 +- packages/router-core/src/service.rs | 2 +- packages/router/Cargo.toml | 2 +- packages/router/src/contexts/router.rs | 2 +- packages/router/src/hooks/use_route.rs | 2 +- packages/router/src/hooks/use_router.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/router-core/Cargo.toml b/packages/router-core/Cargo.toml index 1034a856c..ba5c3cd7d 100644 --- a/packages/router-core/Cargo.toml +++ b/packages/router-core/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-rwlock = "1.3.0" +async-lock = "2.7.0" either = "1.8.0" futures-channel = "0.3.25" futures-util = "0.3.25" diff --git a/packages/router-core/src/service.rs b/packages/router-core/src/service.rs index 725db85e4..0860a50ca 100644 --- a/packages/router-core/src/service.rs +++ b/packages/router-core/src/service.rs @@ -4,7 +4,7 @@ use std::{ sync::{Arc, Weak}, }; -use async_rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use async_lock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use either::Either; use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures_util::StreamExt; diff --git a/packages/router/Cargo.toml b/packages/router/Cargo.toml index 2c91d8008..b607b293f 100644 --- a/packages/router/Cargo.toml +++ b/packages/router/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] [dependencies] anyhow = "1.0.66" -async-rwlock = "1.3.0" +async-lock = "2.7.0" dioxus = { path="../dioxus" } dioxus-router-core = { path = "../router-core"} futures-channel = "0.3.25" diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index 063cc8bc8..cd269540d 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use async_rwlock::RwLock; +use async_lock::RwLock; use dioxus::{core::Component, prelude::ScopeId}; use dioxus_router_core::{RouterMessage, RouterState}; use futures_channel::mpsc::UnboundedSender; diff --git a/packages/router/src/hooks/use_route.rs b/packages/router/src/hooks/use_route.rs index e1162c589..5f13e71a2 100644 --- a/packages/router/src/hooks/use_route.rs +++ b/packages/router/src/hooks/use_route.rs @@ -1,4 +1,4 @@ -use async_rwlock::RwLockReadGuard; +use async_lock::RwLockReadGuard; use dioxus::{core::Component, prelude::ScopeState}; use dioxus_router_core::RouterState; diff --git a/packages/router/src/hooks/use_router.rs b/packages/router/src/hooks/use_router.rs index 667b7b63d..73b89352b 100644 --- a/packages/router/src/hooks/use_router.rs +++ b/packages/router/src/hooks/use_router.rs @@ -1,4 +1,4 @@ -use async_rwlock::RwLockReadGuard; +use async_lock::RwLockReadGuard; use dioxus::{core::Component, prelude::*}; use dioxus_router_core::{ history::{HistoryProvider, MemoryHistory}, From 0b7384ddf2e29709c7b55e1fe633f155536cde1d Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Tue, 11 Apr 2023 19:58:28 +0200 Subject: [PATCH 426/895] document why matching route doctest is ignored --- packages/router-core/src/routes/segment.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/router-core/src/routes/segment.rs b/packages/router-core/src/routes/segment.rs index bcc1fbc4e..846f70495 100644 --- a/packages/router-core/src/routes/segment.rs +++ b/packages/router-core/src/routes/segment.rs @@ -135,6 +135,7 @@ impl Segment { /// Add a matching [`ParameterRoute`] to the [`Segment`]. /// /// ```rust,ignore + /// # // Test is ignored because there are scenarios where no matcher is available. /// # use dioxus_router_core::routes::Segment; /// Segment::empty().matching("some matcher", (true, ContentAtom("matching route content"))); /// ``` From 18c7f9c056239c89f5a6e4e7c4e25d04f86fae25 Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Tue, 11 Apr 2023 20:38:39 +0200 Subject: [PATCH 427/895] reimplement link click event handler prop --- packages/router/src/components/link.rs | 52 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index 193dfa7a3..24374bda8 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use dioxus::prelude::*; use dioxus_router_core::{navigation::NavigationTarget, RouterMessage}; use log::error; @@ -5,7 +7,7 @@ use log::error; use crate::utils::use_router_internal::use_router_internal; /// The properties for a [`Link`]. -#[derive(Debug, Props)] +#[derive(Props)] pub struct LinkProps<'a> { /// A class to apply to the generate HTML anchor tag if the `target` route is active. pub active_class: Option<&'a str>, @@ -28,6 +30,16 @@ pub struct LinkProps<'a> { /// This does not change whether the [`Link`] is active or not. #[props(default)] pub new_tab: bool, + /// The onclick event handler. + pub onclick: Option>, + #[props(default)] + /// Whether the default behavior should be executed if an `onclick` handler is provided. + /// + /// 1. When `onclick` is [`None`] (default if not specified), `onclick_only` has no effect. + /// 2. If `onclick_only` is [`false`] (default if not specified), the provided `onclick` handler + /// will be executed after the links regular functionality. + /// 3. If `onclick_only` is [`true`], only the provided `onclick` handler will be executed. + pub onclick_only: bool, /// The rel attribute for the generated HTML anchor tag. /// /// For external `target`s, this defaults to `noopener noreferrer`. @@ -37,6 +49,23 @@ pub struct LinkProps<'a> { pub target: NavigationTarget, } +impl Debug for LinkProps<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LinkProps") + .field("active_class", &self.active_class) + .field("children", &self.children) + .field("class", &self.class) + .field("exact", &self.exact) + .field("id", &self.id) + .field("new_tab", &self.new_tab) + .field("onclick", &self.onclick.as_ref().map(|_| "onclick is set")) + .field("onclick_only", &self.onclick_only) + .field("rel", &self.rel) + .field("target", &self.target) + .finish() + } +} + /// A link to navigate to another route. /// /// Only works as descendant of a component calling [`use_router`], otherwise it will be inactive. @@ -109,6 +138,8 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { exact, id, new_tab, + onclick, + onclick_only, rel, target, } = cx.props; @@ -152,13 +183,22 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { .or_else(|| is_external.then_some("noopener noreferrer")) .unwrap_or_default(); + let do_default = onclick.is_none() || !onclick_only; + let action = move |event| { + if do_default { + if is_router_nav { + let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); + } + } + + if let Some(handler) = onclick { + handler.call(event); + } + }; + render! { a { - onclick: move |_| { - if is_router_nav { - let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); - } - }, + onclick: action, href: "{href}", prevent_default: "{prevent_default}", class: "{class}", From e24526dab3a80629ac3dc6fbf0fde4322fc8d6e4 Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Tue, 11 Apr 2023 22:07:00 +0200 Subject: [PATCH 428/895] add tests for the link component --- packages/router/tests/via_ssr/link.rs | 286 ++++++++++++++++++++++++++ packages/router/tests/via_ssr/main.rs | 1 + 2 files changed, 287 insertions(+) create mode 100644 packages/router/tests/via_ssr/link.rs diff --git a/packages/router/tests/via_ssr/link.rs b/packages/router/tests/via_ssr/link.rs new file mode 100644 index 000000000..49eb5c327 --- /dev/null +++ b/packages/router/tests/via_ssr/link.rs @@ -0,0 +1,286 @@ +use dioxus::prelude::*; +use dioxus_router::prelude::*; + +fn prepare(link: Component) -> String { + #![allow(non_snake_case)] + + let mut vdom = VirtualDom::new_with_props(App, AppProps { link }); + let _ = vdom.rebuild(); + return dioxus_ssr::render(&vdom); + + #[derive(Props)] + struct AppProps { + link: Component, + } + + impl PartialEq for AppProps { + fn eq(&self, other: &Self) -> bool { + false + } + } + + fn App(cx: Scope) -> Element { + use_router( + cx, + &|| RouterConfiguration { + synchronous: true, + ..Default::default() + }, + &|| Segment::content(comp(cx.props.link)), + ); + + render! { + h1 { "App" } + Outlet { } + } + } +} + +#[test] +fn href_internal() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn href_named() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: named::(), + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn href_external() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "https://dioxuslabs.com/", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="https://dioxuslabs.com/""#, + default = r#"dioxus-prevent-default="""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="noopener noreferrer""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_class() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + class: "test_class", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="test_class""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_active_class_active() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/", + active_class: "active_class", + class: "test_class", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="test_class active_class""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_active_class_inactive() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + active_class: "active_class", + class: "test_class", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="test_class""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_id() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + id: "test_id", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="""#, + id = r#"id="test_id""#, + rel = r#"rel="""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_new_tab() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + new_tab: true, + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="""#, + target = r#"target="_blank""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_new_tab_external() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "https://dioxuslabs.com/", + new_tab: true, + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="https://dioxuslabs.com/""#, + default = r#"dioxus-prevent-default="""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="noopener noreferrer""#, + target = r#"target="_blank""# + ); + + assert_eq!(prepare(content), expected); +} + +#[test] +fn with_rel() { + fn content(cx: Scope) -> Element { + render! { + Link { + target: "/test", + rel: "test_rel", + "Link" + } + } + } + + let expected = format!( + "

App

Link", + href = r#"href="/test""#, + default = r#"dioxus-prevent-default="onclick""#, + class = r#"class="""#, + id = r#"id="""#, + rel = r#"rel="test_rel""#, + target = r#"target="""# + ); + + assert_eq!(prepare(content), expected); +} diff --git a/packages/router/tests/via_ssr/main.rs b/packages/router/tests/via_ssr/main.rs index 6f90f1419..f86bd4eb4 100644 --- a/packages/router/tests/via_ssr/main.rs +++ b/packages/router/tests/via_ssr/main.rs @@ -1 +1,2 @@ +mod link; mod outlet; From d6b9d8f5b65fc0931bd5381ea967fb7f7d487a74 Mon Sep 17 00:00:00 2001 From: Andrew Collins <50530928+ProfXwing@users.noreply.github.com> Date: Tue, 11 Apr 2023 16:45:00 -0400 Subject: [PATCH 429/895] remove rc around webview and add type for desktopcontext --- packages/desktop/src/desktop_context.rs | 23 +++++++++++----------- packages/desktop/src/lib.rs | 26 +++++++++++++------------ packages/desktop/src/shortcut.rs | 4 ++-- packages/desktop/src/webview.rs | 6 ++---- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 35da2eab3..effd9acd1 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -31,8 +31,8 @@ use wry::webview::WebView; pub type ProxyType = EventLoopProxy; /// Get an imperative handle to the current window -pub fn use_window(cx: &ScopeState) -> &Rc { - cx.use_hook(|| cx.consume_context::>()) +pub fn use_window(cx: &ScopeState) -> &DesktopContext { + cx.use_hook(|| cx.consume_context::()) .as_ref() .unwrap() } @@ -51,10 +51,9 @@ pub(crate) type WebviewQueue = Rc>>; /// ```rust, ignore /// let desktop = cx.consume_context::().unwrap(); /// ``` -#[derive(Clone)] -pub struct DesktopContext { +pub struct DesktopService { /// The wry/tao proxy to the current window - pub webview: Rc, + pub webview: WebView, /// The proxy to the event loop pub proxy: ProxyType, @@ -74,8 +73,10 @@ pub struct DesktopContext { pub(crate) views: Rc>>, } +pub type DesktopContext = Rc; + /// A smart pointer to the current window. -impl std::ops::Deref for DesktopContext { +impl std::ops::Deref for DesktopService { type Target = Window; fn deref(&self) -> &Self::Target { @@ -83,9 +84,9 @@ impl std::ops::Deref for DesktopContext { } } -impl DesktopContext { +impl DesktopService { pub(crate) fn new( - webview: Rc, + webview: WebView, proxy: ProxyType, event_loop: EventLoopWindowTarget, webviews: WebviewQueue, @@ -112,7 +113,7 @@ impl DesktopContext { /// You can use this to control other windows from the current window. /// /// Be careful to not create a cycle of windows, or you might leak memory. - pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> Weak { + pub fn new_window(&self, dom: VirtualDom, cfg: Config) -> Weak { let window = create_new_window( cfg, &self.event_loop, @@ -126,10 +127,10 @@ impl DesktopContext { let desktop_context = window .dom .base_scope() - .consume_context::>() + .consume_context::>() .unwrap(); - let id = window.webview.window().id(); + let id = window.desktop_context.webview.window().id(); self.proxy .send_event(UserWindowEvent(EventData::NewWindow, id)) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 270eb1580..fe8ba237e 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -15,9 +15,11 @@ mod webview; pub use cfg::Config; pub use desktop_context::{ - use_window, use_wry_event_handler, DesktopContext, WryEventHandler, WryEventHandlerId, + use_window, use_wry_event_handler, DesktopService, WryEventHandler, WryEventHandlerId, +}; +use desktop_context::{ + DesktopContext, EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers, }; -use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers}; use dioxus_core::*; use dioxus_html::HtmlEvent; pub use eval::{use_eval, EvalResult}; @@ -186,7 +188,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) Event::NewEvents(StartCause::Init) | Event::UserEvent(UserWindowEvent(EventData::NewWindow, _)) => { for handler in queue.borrow_mut().drain(..) { - let id = handler.webview.window().id(); + let id = handler.desktop_context.webview.window().id(); webviews.insert(id, handler); _ = proxy.send_event(UserWindowEvent(EventData::Poll, id)); } @@ -232,12 +234,12 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) view.dom .handle_event(&evt.name, evt.data.into_any(), evt.element, evt.bubbles); - send_edits(view.dom.render_immediate(), &view.webview); + send_edits(view.dom.render_immediate(), &view.desktop_context.webview); } EventData::Ipc(msg) if msg.method() == "initialize" => { let view = webviews.get_mut(&event.1).unwrap(); - send_edits(view.dom.rebuild(), &view.webview); + send_edits(view.dom.rebuild(), &view.desktop_context.webview); } // When the webview chirps back with the result of the eval, we send it to the active receiver @@ -248,7 +250,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) webviews[&event.1] .dom .base_scope() - .consume_context::>() + .consume_context::() .unwrap() .eval .send(msg.params()) @@ -284,8 +286,8 @@ fn create_new_window( shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { let webview = webview::build(&mut cfg, event_loop, proxy.clone()); - let desktop_context = Rc::from(DesktopContext::new( - webview.clone(), + let desktop_context = Rc::from(DesktopService::new( + webview, proxy.clone(), event_loop.clone(), queue.clone(), @@ -295,12 +297,12 @@ fn create_new_window( dom.base_scope().provide_context(desktop_context.clone()); - let id = webview.window().id(); + let id = desktop_context.webview.window().id(); // We want to poll the virtualdom and the event loop at the same time, so the waker will be connected to both WebviewHandler { - webview, + desktop_context, dom, waker: waker::tao_waker(proxy, id), } @@ -308,7 +310,7 @@ fn create_new_window( struct WebviewHandler { dom: VirtualDom, - webview: Rc, + desktop_context: DesktopContext, waker: Waker, } @@ -331,7 +333,7 @@ fn poll_vdom(view: &mut WebviewHandler) { } } - send_edits(view.dom.render_immediate(), &view.webview); + send_edits(view.dom.render_immediate(), &view.desktop_context.webview); } } diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs index e70d13235..8d1c09d1a 100644 --- a/packages/desktop/src/shortcut.rs +++ b/packages/desktop/src/shortcut.rs @@ -10,7 +10,7 @@ use wry::application::{ keyboard::{KeyCode, ModifiersState}, }; -use crate::{use_window, DesktopContext}; +use crate::{desktop_context::DesktopContext, use_window}; #[derive(Clone)] pub(crate) struct ShortcutRegistry { @@ -146,7 +146,7 @@ pub struct ShortcutId { /// A global shortcut. This will be automatically removed when it is dropped. pub struct ShortcutHandle { - desktop: Rc, + desktop: DesktopContext, /// The id of the shortcut pub shortcut_id: ShortcutId, } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 099a2bd94..8e1687374 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use crate::desktop_context::EventData; use crate::protocol; use crate::{desktop_context::UserWindowEvent, Config}; @@ -13,7 +11,7 @@ pub fn build( cfg: &mut Config, event_loop: &EventLoopWindowTarget, proxy: EventLoopProxy, -) -> Rc { +) -> WebView { let builder = cfg.window.clone(); let window = builder.build(event_loop).unwrap(); let file_handler = cfg.file_drop_handler.take(); @@ -82,5 +80,5 @@ pub fn build( webview = webview.with_devtools(true); } - Rc::new(webview.build().unwrap()) + webview.build().unwrap() } From 4bc5d457ae2ed07e41f8813fef1c1ec8842c92a2 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 12 Apr 2023 10:03:55 -0500 Subject: [PATCH 430/895] create custom element test --- packages/native-core/tests/custom_element.rs | 195 +++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 packages/native-core/tests/custom_element.rs diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs new file mode 100644 index 000000000..f1285c8cc --- /dev/null +++ b/packages/native-core/tests/custom_element.rs @@ -0,0 +1,195 @@ +use dioxus::prelude::*; +use dioxus_native_core::{custom_element::CustomElement, prelude::*}; +use dioxus_native_core_macro::partial_derive_state; +use shipyard::Component; +use tokio::time::sleep; + +#[derive(Debug, Clone, PartialEq, Eq, Default, Component)] +pub struct BlablaState { + count: usize, +} + +#[partial_derive_state] +impl State for BlablaState { + type ParentDependencies = (Self,); + type ChildDependencies = (); + type NodeDependencies = (); + + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() + .with_attrs(AttributeMaskBuilder::Some(&["blabla"])) + .with_element(); + + fn update<'a>( + &mut self, + _: NodeView, + _: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _: Vec<::ElementBorrowed<'a>>, + _: &SendAnyMap, + ) -> bool { + if let Some((parent,)) = parent { + if parent.count != 0 { + self.count += 1; + } + } + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Vec<::ElementBorrowed<'a>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.update(node_view, node, parent, children, context); + myself + } +} + +mod dioxus_elements { + macro_rules! builder_constructors { + ( + $( + $(#[$attr:meta])* + $name:ident { + $( + $(#[$attr_method:meta])* + $fil:ident: $vil:ident, + )* + }; + )* + ) => { + $( + #[allow(non_camel_case_types)] + $(#[$attr])* + pub struct $name; + + impl $name { + pub const TAG_NAME: &'static str = stringify!($name); + pub const NAME_SPACE: Option<&'static str> = None; + + $( + pub const $fil: (&'static str, Option<&'static str>, bool) = (stringify!($fil), None, false); + )* + } + + impl GlobalAttributes for $name {} + )* + } + } + + pub trait GlobalAttributes {} + + pub trait SvgAttributes {} + + builder_constructors! { + blabla { + + }; + testing132 { + + }; + } +} + +#[test] +fn native_core_is_okay() { + use std::sync::{Arc, Mutex}; + use std::time::Duration; + + fn app(cx: Scope) -> Element { + let colors = use_state(cx, || vec!["green", "blue", "red"]); + let padding = use_state(cx, || 10); + + use_effect(cx, colors, |colors| async move { + sleep(Duration::from_millis(1000)).await; + colors.with_mut(|colors| colors.reverse()); + }); + + use_effect(cx, padding, |padding| async move { + sleep(Duration::from_millis(10)).await; + padding.with_mut(|padding| { + if *padding < 65 { + *padding += 1; + } else { + *padding = 5; + } + }); + }); + + let _big = colors[0]; + let _mid = colors[1]; + let _small = colors[2]; + + cx.render(rsx! { + blabla { + blabla { + testing132 {} + } + } + }) + } + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap(); + + rt.block_on(async { + let rdom = Arc::new(Mutex::new(RealDom::new([BlablaState::to_type_erased()]))); + rdom.lock() + .unwrap() + .register_custom_element::(); + let mut dioxus_state = DioxusState::create(&mut rdom.lock().unwrap()); + let mut dom = VirtualDom::new(app); + + let mutations = dom.rebuild(); + dioxus_state.apply_mutations(&mut rdom.lock().unwrap(), mutations); + + let ctx = SendAnyMap::new(); + rdom.lock().unwrap().update_state(ctx); + + for _ in 0..10 { + dom.wait_for_work().await; + + let mutations = dom.render_immediate(); + dioxus_state.apply_mutations(&mut rdom.lock().unwrap(), mutations); + + let ctx = SendAnyMap::new(); + rdom.lock().unwrap().update_state(ctx); + } + }); +} + +struct TestElement { + root: NodeId, +} + +impl CustomElement for TestElement { + const NAME: &'static str = "blabla"; + + fn create(dom: &mut RealDom<()>) -> Self { + let root = dom.create_node(ElementNode { + tag: "shadow_root".into(), + namespace: None, + attributes: Default::default(), + listeners: Default::default(), + }); + Self { root: root.id() } + } + + fn root(&self) -> NodeId { + self.root + } + + fn attributes_changed( + &mut self, + _dom: &mut RealDom<()>, + attributes: &dioxus_native_core::node_ref::AttributeMask, + ) { + println!("attributes_changed"); + println!("{:?}", attributes); + } +} From e7fb03f900d166995a2bfa18c4c385187873d7f5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 12 Apr 2023 10:04:18 -0500 Subject: [PATCH 431/895] Merge branch 'upstream' into make-widgets-cross-framework --- examples/counter.rs | 36 ++++++++++++++++++++++++++++++++ packages/desktop/Cargo.toml | 2 +- packages/desktop/src/cfg.rs | 5 +++-- packages/desktop/src/lib.rs | 6 ++++-- packages/desktop/src/protocol.rs | 13 +++++++----- packages/desktop/src/webview.rs | 15 +++++++------ packages/ssr/src/cache.rs | 16 +++++++++++++- packages/ssr/src/renderer.rs | 23 ++++++++++++++++++-- packages/ssr/tests/inner_html.rs | 26 +++++++++++++++++++++++ packages/web/src/cfg.rs | 7 ++++--- 10 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 examples/counter.rs create mode 100644 packages/ssr/tests/inner_html.rs diff --git a/examples/counter.rs b/examples/counter.rs new file mode 100644 index 000000000..f51083a95 --- /dev/null +++ b/examples/counter.rs @@ -0,0 +1,36 @@ +//! Comparison example with leptos' counter example +//! https://github.com/leptos-rs/leptos/blob/main/examples/counters/src/lib.rs + +use dioxus::prelude::*; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let counters = use_state(cx, || vec![0, 0, 0]); + let sum: usize = counters.iter().copied().sum(); + + render! { + div { + button { onclick: move |_| counters.make_mut().push(0), "Add counter" } + button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" } + p { "Total: {sum}" } + for (i, counter) in counters.iter().enumerate() { + li { + button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" } + input { + value: "{counter}", + oninput: move |e| { + if let Ok(value) = e.value.parse::() { + counters.make_mut()[i] = value; + } + } + } + button { onclick: move |_| counters.make_mut()[i] += 1, "+1" } + button { onclick: move |_| { counters.make_mut().remove(i); }, "x" } + } + } + } + } +} diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 7645e4de5..5722a42a2 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -21,7 +21,7 @@ serde = "1.0.136" serde_json = "1.0.79" thiserror = "1.0.30" log = "0.4.14" -wry = { version = "0.23.4" } +wry = { version = "0.27.2" } futures-channel = "0.3.21" tokio = { version = "1.16.1", features = [ "sync", diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 7b37b46d4..d7f1b5dfa 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::PathBuf; use wry::application::window::Icon; @@ -28,7 +29,7 @@ type DropHandler = Box bool>; pub(crate) type WryProtocol = ( String, - Box>) -> WryResult>> + 'static>, + Box>) -> WryResult>> + 'static>, ); impl Config { @@ -98,7 +99,7 @@ impl Config { /// Set a custom protocol pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self where - F: Fn(&HttpRequest>) -> WryResult>> + 'static, + F: Fn(&HttpRequest>) -> WryResult>> + 'static, { self.protocols.push((name, Box::new(handler))); self diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 75c67dd22..434cf3305 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -36,8 +36,8 @@ use tao::{ }; pub use wry; pub use wry::application as tao; -use wry::application::window::WindowId; use wry::webview::WebView; +use wry::{application::window::WindowId, webview::WebContext}; /// Launch the WebView and run the event loop. /// @@ -281,7 +281,7 @@ fn create_new_window( event_handlers: &WindowEventHandlers, shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { - let webview = webview::build(&mut cfg, event_loop, proxy.clone()); + let (webview, web_context) = webview::build(&mut cfg, event_loop, proxy.clone()); dom.base_scope().provide_context(DesktopContext::new( webview.clone(), @@ -299,6 +299,7 @@ fn create_new_window( webview, dom, waker: waker::tao_waker(proxy, id), + web_context, } } @@ -306,6 +307,7 @@ struct WebviewHandler { dom: VirtualDom, webview: Rc, waker: Waker, + web_context: WebContext, } /// Poll the virtualdom until it's pending diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index f8c002a6a..efdc849a5 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,5 +1,8 @@ use dioxus_interpreter_js::INTERPRETER_JS; -use std::path::{Path, PathBuf}; +use std::{ + borrow::Cow, + path::{Path, PathBuf}, +}; use wry::{ http::{status::StatusCode, Request, Response}, Result, @@ -27,7 +30,7 @@ pub(super) fn desktop_handler( custom_head: Option, custom_index: Option, root_name: &str, -) -> Result>> { +) -> 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. @@ -53,7 +56,7 @@ pub(super) fn desktop_handler( return Response::builder() .header("Content-Type", "text/html") - .body(body) + .body(Cow::from(body)) .map_err(From::from); } @@ -72,13 +75,13 @@ pub(super) fn desktop_handler( if asset.exists() { return Response::builder() .header("Content-Type", get_mime_from_path(&asset)?) - .body(std::fs::read(asset)?) + .body(Cow::from(std::fs::read(asset)?)) .map_err(From::from); } Response::builder() .status(StatusCode::NOT_FOUND) - .body(String::from("Not Found").into_bytes()) + .body(Cow::from(String::from("Not Found").into_bytes())) .map_err(From::from) } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 099a2bd94..c6909972f 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -7,13 +7,13 @@ use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use wry; pub use wry::application as tao; use wry::application::window::Window; -use wry::webview::{WebView, WebViewBuilder}; +use wry::webview::{WebContext, WebView, WebViewBuilder}; pub fn build( cfg: &mut Config, event_loop: &EventLoopWindowTarget, proxy: EventLoopProxy, -) -> Rc { +) -> (Rc, WebContext) { let builder = cfg.window.clone(); let window = builder.build(event_loop).unwrap(); let file_handler = cfg.file_drop_handler.take(); @@ -33,6 +33,8 @@ pub fn build( )); } + let mut web_context = WebContext::new(cfg.data_dir.clone()); + let mut webview = WebViewBuilder::new(window) .unwrap() .with_transparent(cfg.window.window.transparent) @@ -52,11 +54,8 @@ pub fn build( .as_ref() .map(|handler| handler(window, evet)) .unwrap_or_default() - }); - - // These are commented out because wry is currently broken in wry - // let mut web_context = WebContext::new(cfg.data_dir.clone()); - // .with_web_context(&mut web_context); + }) + .with_web_context(&mut web_context); for (name, handler) in cfg.protocols.drain(..) { webview = webview.with_custom_protocol(name, handler) @@ -82,5 +81,5 @@ pub fn build( webview = webview.with_devtools(true); } - Rc::new(webview.build().unwrap()) + (Rc::new(webview.build().unwrap()), web_context) } diff --git a/packages/ssr/src/cache.rs b/packages/ssr/src/cache.rs index e261d3b65..a67fd5f22 100644 --- a/packages/ssr/src/cache.rs +++ b/packages/ssr/src/cache.rs @@ -23,6 +23,8 @@ pub enum Segment { // This will be true if there are static styles inside_style_tag: bool, }, + /// A marker for where to insert a dynamic inner html + InnerHtmlMarker, } impl std::fmt::Write for StringChain { @@ -69,6 +71,9 @@ impl StringCache { write!(chain, "<{tag}")?; // we need to collect the styles and write them at the end let mut styles = Vec::new(); + // we need to collect the inner html and write it at the end + let mut inner_html = None; + // we need to keep track of if we have dynamic attrs to know if we need to insert a style and inner_html marker let mut has_dynamic_attrs = false; for attr in *attrs { match attr { @@ -77,7 +82,9 @@ impl StringCache { value, namespace, } => { - if let Some("style") = namespace { + if *name == "dangerous_inner_html" { + inner_html = Some(value); + } else if let Some("style") = namespace { styles.push((name, value)); } else { write!(chain, " {name}=\"{value}\"")?; @@ -110,6 +117,13 @@ impl StringCache { write!(chain, "/>")?; } else { write!(chain, ">")?; + // Write the static inner html, or insert a marker if dynamic inner html is possible + if let Some(inner_html) = inner_html { + chain.write_str(inner_html)?; + } else if has_dynamic_attrs { + chain.segments.push(Segment::InnerHtmlMarker); + } + for child in *children { Self::recurse(child, cur_path, root_idx, chain)?; } diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index be4025dba..cfa08aee4 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -70,6 +70,8 @@ impl Renderer { .or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap())) .clone(); + let mut inner_html = None; + // We need to keep track of the dynamic styles so we can insert them into the right place let mut accumulated_dynamic_styles = Vec::new(); @@ -77,7 +79,9 @@ impl Renderer { match segment { Segment::Attr(idx) => { let attr = &template.dynamic_attrs[*idx]; - if attr.namespace == Some("style") { + if attr.name == "dangerous_inner_html" { + inner_html = Some(attr); + } else if attr.namespace == Some("style") { accumulated_dynamic_styles.push(attr); } else { match attr.value { @@ -165,6 +169,19 @@ impl Renderer { accumulated_dynamic_styles.clear(); } } + + Segment::InnerHtmlMarker => { + if let Some(inner_html) = inner_html.take() { + let inner_html = &inner_html.value; + match inner_html { + AttributeValue::Text(value) => write!(buf, "{}", value)?, + AttributeValue::Bool(value) => write!(buf, "{}", value)?, + AttributeValue::Float(f) => write!(buf, "{}", f)?, + AttributeValue::Int(i) => write!(buf, "{}", i)?, + _ => {} + } + } + } } } @@ -208,7 +225,9 @@ fn to_string_works() { StyleMarker { inside_style_tag: false, }, - PreRendered(">Hello world 1 -->".into(),), + PreRendered(">".into()), + InnerHtmlMarker, + PreRendered("Hello world 1 -->".into(),), Node(0,), PreRendered( "<-- Hello world 2

nest 1
nest 2
".into(), diff --git a/packages/ssr/tests/inner_html.rs b/packages/ssr/tests/inner_html.rs new file mode 100644 index 000000000..11fb94746 --- /dev/null +++ b/packages/ssr/tests/inner_html.rs @@ -0,0 +1,26 @@ +use dioxus::prelude::*; + +#[test] +fn static_inner_html() { + fn app(cx: Scope) -> Element { + render! { div { dangerous_inner_html: "
1234
" } } + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); +} + +#[test] +fn dynamic_inner_html() { + fn app(cx: Scope) -> Element { + let inner_html = "
1234
"; + render! { div { dangerous_inner_html: "{inner_html}" } } + } + + let mut dom = VirtualDom::new(app); + _ = dom.rebuild(); + + assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); +} diff --git a/packages/web/src/cfg.rs b/packages/web/src/cfg.rs index 7e47ed461..7483a7a8b 100644 --- a/packages/web/src/cfg.rs +++ b/packages/web/src/cfg.rs @@ -49,15 +49,16 @@ impl Config { /// Set the name of the element that Dioxus will use as the root. /// - /// This is akint to calling React.render() on the element with the specified name. + /// This is akin to calling React.render() on the element with the specified name. pub fn rootname(mut self, name: impl Into) -> Self { self.rootname = name.into(); self } - /// Set the name of the element that Dioxus will use as the root. + /// Sets a string cache for wasm bindgen to [intern](https://docs.rs/wasm-bindgen/0.2.84/wasm_bindgen/fn.intern.html). This can help reduce the time it takes for wasm bindgen to pass + /// strings from rust to javascript. This can significantly improve pefromance when passing strings to javascript, but can have a negative impact on startup time. /// - /// This is akint to calling React.render() on the element with the specified name. + /// > Currently this cache is only used when creating static elements and attributes. pub fn with_string_cache(mut self, cache: Vec) -> Self { self.cached_strings = cache; self From 788c00274eb1ba6fe3136a31c21028fa64556599 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 12 Apr 2023 10:05:09 -0500 Subject: [PATCH 432/895] create a shadow dom when a custom element is mounted --- packages/native-core/src/custom_element.rs | 72 +++-- packages/native-core/src/node_ref.rs | 6 +- packages/native-core/src/real_dom.rs | 9 +- packages/native-core/src/tree.rs | 2 +- packages/native-core/tests/custom_element.rs | 303 ++++++++++++++----- 5 files changed, 295 insertions(+), 97 deletions(-) diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs index f829d89f0..62d7e5368 100644 --- a/packages/native-core/src/custom_element.rs +++ b/packages/native-core/src/custom_element.rs @@ -1,3 +1,6 @@ +//! A custom element is a controlled element that renders to a shadow DOM. +//! Each custom element is registered with a element name + use std::sync::{Arc, RwLock}; use rustc_hash::FxHashMap; @@ -7,11 +10,12 @@ use crate::{ node::{FromAnyValue, NodeType}, node_ref::AttributeMask, prelude::{NodeImmutable, NodeMut, RealDom}, + tree::TreeMut, NodeId, }; pub(crate) struct CustomElementRegistry { - builders: FxHashMap<&'static str, CustomElementBuilder>, + builders: FxHashMap<(&'static str, Option<&'static str>), CustomElementBuilder>, } impl Default for CustomElementRegistry { @@ -25,7 +29,7 @@ impl Default for CustomElementRegistry { impl CustomElementRegistry { pub fn register>(&mut self) { self.builders.insert( - W::NAME, + (W::NAME, W::NAMESPACE), CustomElementBuilder { create: |dom| Box::new(W::create(dom)), }, @@ -34,17 +38,26 @@ impl CustomElementRegistry { pub fn add_shadow_dom(&self, mut node: NodeMut) { let element_tag = if let NodeType::Element(el) = &*node.node_type() { - Some(el.tag.clone()) + Some((el.tag.clone(), el.namespace.clone())) } else { None }; - if let Some(element_tag) = element_tag { - if let Some(builder) = self.builders.get(element_tag.as_str()) { + if let Some((tag, ns)) = element_tag { + if let Some(builder) = self.builders.get(&(tag.as_str(), ns.as_deref())) { let boxed_widget = { let dom = node.real_dom_mut(); (builder.create)(dom) }; + let shadow_roots = boxed_widget.roots(); + + let light_id = node.id(); + node.real_dom_mut().tree_mut().create_subtree( + light_id, + shadow_roots, + boxed_widget.slot(), + ); + let boxed_widget = CustomElementManager { inner: Arc::new(RwLock::new(boxed_widget)), }; @@ -64,11 +77,14 @@ pub trait CustomElement: Send + Sync + 'stat /// The tag the widget is registered under. const NAME: &'static str; - /// Create a new widget without mounting it. + /// The namespace the widget is registered under. + const NAMESPACE: Option<&'static str> = None; + + /// Create a new widget *without mounting* it. fn create(dom: &mut RealDom) -> Self; /// The root node of the widget. This must be static once the element is created. - fn root(&self) -> NodeId; + fn roots(&self) -> Vec; /// The slot to render children of the element into. This must be static once the element is created. fn slot(&self) -> Option { @@ -76,7 +92,7 @@ pub trait CustomElement: Send + Sync + 'stat } /// Called when the attributes of the widget are changed. - fn attributes_changed(&mut self, _dom: &mut RealDom, _attributes: &AttributeMask); + fn attributes_changed(&mut self, light_node: NodeMut, attributes: &AttributeMask); } /// A factory for creating widgets @@ -86,6 +102,9 @@ trait ElementFactory, V: FromAnyValue + Send + Sync = /// The tag the widget is registered under. const NAME: &'static str; + /// The namespace the widget is registered under. + const NAMESPACE: Option<&'static str> = None; + /// Create a new widget. fn create(dom: &mut RealDom) -> W; } @@ -93,6 +112,8 @@ trait ElementFactory, V: FromAnyValue + Send + Sync = impl, V: FromAnyValue + Send + Sync> ElementFactory for W { const NAME: &'static str = W::NAME; + const NAMESPACE: Option<&'static str> = W::NAMESPACE; + fn create(dom: &mut RealDom) -> Self { Self::create(dom) } @@ -101,36 +122,51 @@ impl, V: FromAnyValue + Send + Sync> ElementFactory fo /// A trait for updating widgets trait CustomElementUpdater: Send + Sync + 'static { /// Called when the attributes of the widget are changed. - fn attributes_changed(&mut self, dom: &mut RealDom, attributes: &AttributeMask); + fn attributes_changed(&mut self, light_root: NodeMut, attributes: &AttributeMask); /// The root node of the widget. - fn root(&self) -> NodeId; + fn roots(&self) -> Vec; + + /// The slot to render children of the element into. + fn slot(&self) -> Option; } impl, V: FromAnyValue + Send + Sync> CustomElementUpdater for W { - fn attributes_changed(&mut self, root: &mut RealDom, attributes: &AttributeMask) { - self.attributes_changed(root, attributes); + fn attributes_changed(&mut self, light_root: NodeMut, attributes: &AttributeMask) { + self.attributes_changed(light_root, attributes); } - fn root(&self) -> NodeId { - self.root() + fn roots(&self) -> Vec { + self.roots() + } + + fn slot(&self) -> Option { + self.slot() } } +/// A concrete structure for managing a any widget. #[derive(Component, Clone)] pub struct CustomElementManager { inner: Arc>>>, } impl CustomElementManager { - pub fn root(&self) -> NodeId { - self.inner.read().unwrap().root() + /// The root node of the widget's shadow DOM. + pub fn roots(&self) -> Vec { + self.inner.read().unwrap().roots() } - pub fn on_attributes_changed(&self, dom: &mut RealDom, attributes: &AttributeMask) { + /// The slot to render children of the element into. + pub fn slot(&self) -> Option { + self.inner.read().unwrap().slot() + } + + /// Update the custom element based on attributes changed. + pub fn on_attributes_changed(&self, light_root: NodeMut, attributes: &AttributeMask) { self.inner .write() .unwrap() - .attributes_changed(dom, attributes); + .attributes_changed(light_root, attributes); } } diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index a1a309622..156ecdbd6 100644 --- a/packages/native-core/src/node_ref.rs +++ b/packages/native-core/src/node_ref.rs @@ -60,7 +60,7 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> { NodeType::Element(ElementNode { attributes, .. }) => Some( attributes .iter() - .filter(move |(attr, _)| self.mask.attritutes.contains_attribute(&attr.name)) + .filter(move |(attr, _)| self.mask.attritutes.contains(&attr.name)) .map(|(attr, val)| OwnedAttributeView { attribute: attr, value: val, @@ -107,8 +107,8 @@ pub enum AttributeMask { } impl AttributeMask { - /// Check if the given attribute is visible - fn contains_attribute(&self, attr: &str) -> bool { + /// Check if the mask contains the given attribute + pub fn contains(&self, attr: &str) -> bool { match self { AttributeMask::All => true, AttributeMask::Some(attrs) => attrs.contains(attr), diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 490e04dc6..bdcd10d55 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -304,12 +304,11 @@ impl RealDom { }; // call custom element watchers - let custom_element_manager = { - let node = self.get_mut(*node_id).unwrap(); - node.get::>().map(|x| x.clone()) - }; + let node = self.get_mut(*node_id).unwrap(); + let custom_element_manager = + node.get::>().map(|x| x.clone()); if let Some(custom_element_manager) = custom_element_manager { - custom_element_manager.on_attributes_changed(self, mask.attributes()); + custom_element_manager.on_attributes_changed(node, mask.attributes()); } } } diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index e0b32f28d..1f46216b2 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -294,7 +294,7 @@ fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 { .expect("Attempted to read a slot that does not exist") + 1 } else { - panic!("Attempted to read the height of a shadow_tree without a slot"); + panic!("Attempted to read the height of a child of a node with a shadow tree, but the shadow tree does not have a slot. Every shadow tree attached to a node with children must have a slot.") } } None => parent.height + 1, diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs index f1285c8cc..3aa1b7462 100644 --- a/packages/native-core/tests/custom_element.rs +++ b/packages/native-core/tests/custom_element.rs @@ -2,21 +2,23 @@ use dioxus::prelude::*; use dioxus_native_core::{custom_element::CustomElement, prelude::*}; use dioxus_native_core_macro::partial_derive_state; use shipyard::Component; -use tokio::time::sleep; -#[derive(Debug, Clone, PartialEq, Eq, Default, Component)] -pub struct BlablaState { - count: usize, +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Component)] +pub struct ColorState { + color: usize, } #[partial_derive_state] -impl State for BlablaState { +impl State for ColorState { type ParentDependencies = (Self,); type ChildDependencies = (); type NodeDependencies = (); + // The color state should not be effected by the shadow dom + const TRAVERSE_SHADOW_DOM: bool = false; + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() - .with_attrs(AttributeMaskBuilder::Some(&["blabla"])) + .with_attrs(AttributeMaskBuilder::Some(&["color"])) .with_element(); fn update<'a>( @@ -28,8 +30,70 @@ impl State for BlablaState { _: &SendAnyMap, ) -> bool { if let Some((parent,)) = parent { - if parent.count != 0 { - self.count += 1; + self.color = parent.color; + } + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Vec<::ElementBorrowed<'a>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.update(node_view, node, parent, children, context); + myself + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Component)] +pub struct LayoutState { + size: usize, +} + +#[partial_derive_state] +impl State for LayoutState { + type ParentDependencies = (Self,); + type ChildDependencies = (); + type NodeDependencies = (); + + // The layout state should be effected by the shadow dom + const TRAVERSE_SHADOW_DOM: bool = true; + + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() + .with_attrs(AttributeMaskBuilder::Some(&["size"])) + .with_element(); + + fn update<'a>( + &mut self, + view: NodeView, + _: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _: Vec<::ElementBorrowed<'a>>, + _: &SendAnyMap, + ) -> bool { + println!( + "Updating layout state @{:?} {:?}", + parent.as_ref().map(|(p,)| p.size), + view.node_id() + ); + if let Some(size) = view + .attributes() + .into_iter() + .flatten() + .find(|attr| attr.attribute.name == "size") + { + self.size = size + .value + .as_float() + .or_else(|| size.value.as_int().map(|i| i as f64)) + .or_else(|| size.value.as_text().and_then(|i| i.parse().ok())) + .unwrap_or(0.0) as usize; + } else if let Some((parent,)) = parent { + if parent.size > 0 { + self.size -= 1; } } true @@ -66,6 +130,7 @@ mod dioxus_elements { $(#[$attr])* pub struct $name; + #[allow(non_upper_case_globals)] impl $name { pub const TAG_NAME: &'static str = stringify!($name); pub const NAME_SPACE: Option<&'static str> = None; @@ -85,47 +150,110 @@ mod dioxus_elements { pub trait SvgAttributes {} builder_constructors! { - blabla { - + customelementslot { + size: attr, + }; + customelementnoslot { }; testing132 { - }; } } +struct CustomElementWithSlot { + root: NodeId, + slot: NodeId, +} + +impl CustomElement for CustomElementWithSlot { + const NAME: &'static str = "customelementslot"; + + fn create(dom: &mut RealDom<()>) -> Self { + let child = dom.create_node(ElementNode { + tag: "div".into(), + namespace: None, + attributes: Default::default(), + listeners: Default::default(), + }); + let slot_id = child.id(); + let mut root = dom.create_node(ElementNode { + tag: "div".into(), + namespace: None, + attributes: Default::default(), + listeners: Default::default(), + }); + root.add_child(slot_id); + + Self { + root: root.id(), + slot: slot_id, + } + } + + fn slot(&self) -> Option { + Some(self.slot) + } + + fn roots(&self) -> Vec { + vec![self.root] + } + + fn attributes_changed( + &mut self, + node: NodeMut<()>, + attributes: &dioxus_native_core::node_ref::AttributeMask, + ) { + println!("attributes_changed"); + println!("{:?}", attributes); + println!("{:?}: {:#?}", node.id(), &*node.node_type()); + } +} + +struct CustomElementWithNoSlot { + root: NodeId, +} + +impl CustomElement for CustomElementWithNoSlot { + const NAME: &'static str = "customelementnoslot"; + + fn create(dom: &mut RealDom<()>) -> Self { + let root = dom.create_node(ElementNode { + tag: "div".into(), + namespace: None, + attributes: Default::default(), + listeners: Default::default(), + }); + Self { root: root.id() } + } + + fn roots(&self) -> Vec { + vec![self.root] + } + + fn attributes_changed( + &mut self, + node: NodeMut<()>, + attributes: &dioxus_native_core::node_ref::AttributeMask, + ) { + println!("attributes_changed"); + println!("{:?}", attributes); + println!("{:?}: {:#?}", node.id(), &*node.node_type()); + } +} + #[test] -fn native_core_is_okay() { - use std::sync::{Arc, Mutex}; - use std::time::Duration; - +fn custom_elements_work() { fn app(cx: Scope) -> Element { - let colors = use_state(cx, || vec!["green", "blue", "red"]); - let padding = use_state(cx, || 10); + let count = use_state(cx, || 0); - use_effect(cx, colors, |colors| async move { - sleep(Duration::from_millis(1000)).await; - colors.with_mut(|colors| colors.reverse()); + use_future!(cx, |count| async move { + count.with_mut(|count| *count += 1); }); - use_effect(cx, padding, |padding| async move { - sleep(Duration::from_millis(10)).await; - padding.with_mut(|padding| { - if *padding < 65 { - *padding += 1; - } else { - *padding = 5; - } - }); - }); - - let _big = colors[0]; - let _mid = colors[1]; - let _small = colors[2]; - cx.render(rsx! { - blabla { - blabla { + customelementslot { + size: "{count}", + customelementslot { testing132 {} } } @@ -138,58 +266,93 @@ fn native_core_is_okay() { .unwrap(); rt.block_on(async { - let rdom = Arc::new(Mutex::new(RealDom::new([BlablaState::to_type_erased()]))); - rdom.lock() - .unwrap() - .register_custom_element::(); - let mut dioxus_state = DioxusState::create(&mut rdom.lock().unwrap()); + let mut rdom = RealDom::new([LayoutState::to_type_erased(), ColorState::to_type_erased()]); + rdom.register_custom_element::(); + let mut dioxus_state = DioxusState::create(&mut rdom); let mut dom = VirtualDom::new(app); let mutations = dom.rebuild(); - dioxus_state.apply_mutations(&mut rdom.lock().unwrap(), mutations); + dioxus_state.apply_mutations(&mut rdom, mutations); let ctx = SendAnyMap::new(); - rdom.lock().unwrap().update_state(ctx); + rdom.update_state(ctx); for _ in 0..10 { dom.wait_for_work().await; let mutations = dom.render_immediate(); - dioxus_state.apply_mutations(&mut rdom.lock().unwrap(), mutations); + dioxus_state.apply_mutations(&mut rdom, mutations); let ctx = SendAnyMap::new(); - rdom.lock().unwrap().update_state(ctx); + rdom.update_state(ctx); + + // render... + rdom.traverse_depth_first(|node| { + let node_type = &*node.node_type(); + let indent = " ".repeat(node.height() as usize); + let color = *node.get::().unwrap(); + let size = *node.get::().unwrap(); + let id = node.id(); + println!("{indent}{id:?} {color:?} {size:?} {node_type:?}"); + }); } }); } -struct TestElement { - root: NodeId, +#[test] +#[should_panic] +fn slotless_custom_element_cant_have_children() { + fn app(cx: Scope) -> Element { + cx.render(rsx! { + customelementnoslot { + testing132 {} + } + }) + } + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap(); + + rt.block_on(async { + let mut rdom = RealDom::new([LayoutState::to_type_erased(), ColorState::to_type_erased()]); + rdom.register_custom_element::(); + let mut dioxus_state = DioxusState::create(&mut rdom); + let mut dom = VirtualDom::new(app); + + let mutations = dom.rebuild(); + dioxus_state.apply_mutations(&mut rdom, mutations); + + let ctx = SendAnyMap::new(); + rdom.update_state(ctx); + }); } -impl CustomElement for TestElement { - const NAME: &'static str = "blabla"; - - fn create(dom: &mut RealDom<()>) -> Self { - let root = dom.create_node(ElementNode { - tag: "shadow_root".into(), - namespace: None, - attributes: Default::default(), - listeners: Default::default(), - }); - Self { root: root.id() } +#[test] +fn slotless_custom_element() { + fn app(cx: Scope) -> Element { + cx.render(rsx! { + customelementnoslot { + } + }) } - fn root(&self) -> NodeId { - self.root - } + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap(); - fn attributes_changed( - &mut self, - _dom: &mut RealDom<()>, - attributes: &dioxus_native_core::node_ref::AttributeMask, - ) { - println!("attributes_changed"); - println!("{:?}", attributes); - } + rt.block_on(async { + let mut rdom = RealDom::new([LayoutState::to_type_erased(), ColorState::to_type_erased()]); + rdom.register_custom_element::(); + let mut dioxus_state = DioxusState::create(&mut rdom); + let mut dom = VirtualDom::new(app); + + let mutations = dom.rebuild(); + dioxus_state.apply_mutations(&mut rdom, mutations); + + let ctx = SendAnyMap::new(); + rdom.update_state(ctx); + }); } From 4e582d0374509834a4b262957dca99da7813aff8 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 12 Apr 2023 11:35:57 -0500 Subject: [PATCH 433/895] custom element test passing --- packages/native-core-macro/src/lib.rs | 10 ++-- packages/native-core/examples/custom_attr.rs | 2 +- packages/native-core/examples/font_size.rs | 2 +- packages/native-core/examples/simple.rs | 2 +- .../native-core/examples/simple_dioxus.rs | 2 +- packages/native-core/src/passes.rs | 35 +++++++---- packages/native-core/src/real_dom.rs | 52 +++++++++++------ packages/native-core/src/tree.rs | 47 ++++++++++++--- .../tests/called_minimally_on_build.rs | 2 +- packages/native-core/tests/custom_element.rs | 58 ++++++++++++++----- 10 files changed, 155 insertions(+), 57 deletions(-) diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index e75a1485d..ff0e4629d 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -224,14 +224,14 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { let get_parent_view = { if parent_dependencies.is_empty() { quote! { - let raw_parent = tree.parent_id(id).map(|_| ()); + let raw_parent = tree.parent_id_advanced(id, Self::TRAVERSE_SHADOW_DOM).map(|_| ()); } } else { let temps = (0..parent_dependencies.len()) .map(|i| format_ident!("__temp{}", i)) .collect::>(); quote! { - let raw_parent = tree.parent_id(id).and_then(|parent_id| { + let raw_parent = tree.parent_id_advanced(id, Self::TRAVERSE_SHADOW_DOM).and_then(|parent_id| { let raw_parent: Option<(#(*const #parent_dependencies,)*)> = (#(&#parent_view,)*).get(parent_id).ok().map(|c| { let (#(#temps,)*) = c; (#(#temps as *const _,)*) @@ -261,14 +261,14 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { let get_child_view = { if child_dependencies.is_empty() { quote! { - let raw_children: Vec<_> = tree.children_ids(id).into_iter().map(|_| ()).collect(); + let raw_children: Vec<_> = tree.children_ids_advanced(id, Self::TRAVERSE_SHADOW_DOM).into_iter().map(|_| ()).collect(); } } else { let temps = (0..child_dependencies.len()) .map(|i| format_ident!("__temp{}", i)) .collect::>(); quote! { - let raw_children: Vec<_> = tree.children_ids(id).into_iter().filter_map(|id| { + let raw_children: Vec<_> = tree.children_ids_advanced(id, Self::TRAVERSE_SHADOW_DOM).into_iter().filter_map(|id| { let raw_children: Option<(#(*const #child_dependencies,)*)> = (#(&#child_view,)*).get(id).ok().map(|c| { let (#(#temps,)*) = c; (#(#temps as *const _,)*) @@ -336,7 +336,7 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream { let (#(#split_views,)*) = data; let tree = run_view.tree.clone(); let node_types = run_view.node_type.clone(); - dioxus_native_core::prelude::run_pass(type_id, dependants.clone(), pass_direction, run_view, Self::TRAVERSE_SHADOW_DOM, |id, context| { + dioxus_native_core::prelude::run_pass(type_id, dependants.clone(), pass_direction, run_view, |id, context| { let node_data: &NodeType<_> = node_types.get(id).unwrap_or_else(|err| panic!("Failed to get node type {:?}", err)); // get all of the states from the tree view // Safety: No node has itself as a parent or child. diff --git a/packages/native-core/examples/custom_attr.rs b/packages/native-core/examples/custom_attr.rs index 5a1fcfb8c..ee78a69f4 100644 --- a/packages/native-core/examples/custom_attr.rs +++ b/packages/native-core/examples/custom_attr.rs @@ -215,7 +215,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(|node| { + rdom.traverse_depth_first(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/font_size.rs b/packages/native-core/examples/font_size.rs index 937db0c17..4ff6b876d 100644 --- a/packages/native-core/examples/font_size.rs +++ b/packages/native-core/examples/font_size.rs @@ -160,7 +160,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(|node| { + rdom.traverse_depth_first(true, |node| { let indent = " ".repeat(node.height() as usize); let font_size = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/simple.rs b/packages/native-core/examples/simple.rs index 469147c35..b44f05e63 100644 --- a/packages/native-core/examples/simple.rs +++ b/packages/native-core/examples/simple.rs @@ -206,7 +206,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(|node| { + rdom.traverse_depth_first(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/simple_dioxus.rs b/packages/native-core/examples/simple_dioxus.rs index fa1b202dd..c5aebd5d3 100644 --- a/packages/native-core/examples/simple_dioxus.rs +++ b/packages/native-core/examples/simple_dioxus.rs @@ -234,7 +234,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(|node| { + rdom.traverse_depth_first(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 383cdadd2..a76dbc61c 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -153,6 +153,7 @@ pub trait State: Any + Send + Sync { dependants: Default::default(), mask: node_mask, pass_direction: pass_direction::(), + enter_shadow_dom: Self::TRAVERSE_SHADOW_DOM, workload: Self::workload_system, phantom: PhantomData, } @@ -193,7 +194,6 @@ pub fn run_pass( dependants: Arc, pass_direction: PassDirection, view: RunPassView, - enter_shadow_dom: bool, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool, ) { let RunPassView { @@ -232,28 +232,42 @@ pub fn run_pass( } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct Dependant { + pub(crate) type_id: TypeId, + pub(crate) enter_shadow_dom: bool, +} + /// The states that depend on this state #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Dependants { /// The states in the parent direction that should be invalidated when this state is invalidated - pub parent: Vec, + pub(crate) parent: Vec, /// The states in the child direction that should be invalidated when this state is invalidated - pub child: Vec, + pub(crate) child: Vec, /// The states in the node direction that should be invalidated when this state is invalidated - pub node: Vec, + pub(crate) node: Vec, } impl Dependants { fn mark_dirty(&self, dirty: &DirtyNodeStates, id: NodeId, tree: &impl TreeRef, height: u16) { - for dependant in &self.child { - for id in tree.children_ids(id) { - dirty.insert(*dependant, id, height + 1); + for &Dependant { + type_id, + enter_shadow_dom, + } in &self.child + { + for id in tree.children_ids_advanced(id, enter_shadow_dom) { + dirty.insert(type_id, id, height + 1); } } - for dependant in &self.parent { - if let Some(id) = tree.parent_id(id) { - dirty.insert(*dependant, id, height - 1); + for &Dependant { + type_id, + enter_shadow_dom, + } in &self.parent + { + if let Some(id) = tree.parent_id_advanced(id, enter_shadow_dom) { + dirty.insert(type_id, id, height - 1); } } @@ -273,6 +287,7 @@ pub struct TypeErasedState { pub(crate) mask: NodeMask, pub(crate) workload: fn(TypeId, Arc, PassDirection) -> WorkloadSystem, pub(crate) pass_direction: PassDirection, + pub(crate) enter_shadow_dom: bool, phantom: PhantomData, } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 8f5967789..e885963d1 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -16,7 +16,7 @@ use crate::node::{ }; use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::{AttributeWatcher, NodeWatcher}; -use crate::passes::{DirtyNodeStates, PassDirection, TypeErasedState}; +use crate::passes::{Dependant, DirtyNodeStates, PassDirection, TypeErasedState}; use crate::prelude::AttributeMaskBuilder; use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView}; use crate::NodeId; @@ -128,19 +128,25 @@ impl RealDom { let (current, before) = before.split_last_mut().unwrap(); for state in before.iter_mut().chain(after.iter_mut()) { let dependants = Arc::get_mut(&mut state.dependants).unwrap(); + + let current_dependant = Dependant { + type_id: current.this_type_id, + enter_shadow_dom: current.enter_shadow_dom, + }; + // If this node depends on the other state as a parent, then the other state should update its children of the current type when it is invalidated if current .parent_dependancies_ids .contains(&state.this_type_id) - && !dependants.child.contains(¤t.this_type_id) + && !dependants.child.contains(¤t_dependant) { - dependants.child.push(current.this_type_id); + dependants.child.push(current_dependant); } // If this node depends on the other state as a child, then the other state should update its parent of the current type when it is invalidated if current.child_dependancies_ids.contains(&state.this_type_id) - && !dependants.parent.contains(¤t.this_type_id) + && !dependants.parent.contains(¤t_dependant) { - dependants.parent.push(current.this_type_id); + dependants.parent.push(current_dependant); } // If this node depends on the other state as a sibling, then the other state should update its siblings of the current type when it is invalidated if current.node_dependancies_ids.contains(&state.this_type_id) @@ -151,15 +157,19 @@ impl RealDom { } // If the current state depends on itself, then it should update itself when it is invalidated let dependants = Arc::get_mut(&mut current.dependants).unwrap(); + let current_dependant = Dependant { + type_id: current.this_type_id, + enter_shadow_dom: current.enter_shadow_dom, + }; match current.pass_direction { PassDirection::ChildToParent => { - if !dependants.parent.contains(¤t.this_type_id) { - dependants.parent.push(current.this_type_id); + if !dependants.parent.contains(¤t_dependant) { + dependants.parent.push(current_dependant); } } PassDirection::ParentToChild => { - if !dependants.child.contains(¤t.this_type_id) { - dependants.child.push(current.this_type_id); + if !dependants.child.contains(¤t_dependant) { + dependants.child.push(current_dependant); } } _ => {} @@ -371,27 +381,27 @@ impl RealDom { } /// Traverses the dom in a depth first manner, calling the provided function on each node. - pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef)) { + pub fn traverse_depth_first(&self, enter_shadow_doms: bool, mut f: impl FnMut(NodeRef)) { let mut stack = vec![self.root_id()]; let tree = self.tree_ref(); while let Some(id) = stack.pop() { if let Some(node) = self.get(id) { f(node); - let children = tree.children_ids(id); + let children = tree.children_ids_advanced(id, enter_shadow_doms); stack.extend(children.iter().copied().rev()); } } } /// Traverses the dom in a breadth first manner, calling the provided function on each node. - pub fn traverse_breadth_first(&self, mut f: impl FnMut(NodeRef)) { + pub fn traverse_breadth_first(&self, enter_shadow_doms: bool, mut f: impl FnMut(NodeRef)) { let mut queue = VecDeque::new(); queue.push_back(self.root_id()); let tree = self.tree_ref(); while let Some(id) = queue.pop_front() { if let Some(node) = self.get(id) { f(node); - let children = tree.children_ids(id); + let children = tree.children_ids_advanced(id, enter_shadow_doms); for id in children { queue.push_back(id); } @@ -400,11 +410,15 @@ impl RealDom { } /// Traverses the dom in a depth first manner mutably, calling the provided function on each node. - pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(NodeMut)) { + pub fn traverse_depth_first_mut( + &mut self, + enter_shadow_doms: bool, + mut f: impl FnMut(NodeMut), + ) { let mut stack = vec![self.root_id()]; while let Some(id) = stack.pop() { let tree = self.tree_ref(); - let mut children = tree.children_ids(id); + let mut children = tree.children_ids_advanced(id, enter_shadow_doms); drop(tree); children.reverse(); if let Some(node) = self.get_mut(id) { @@ -416,12 +430,16 @@ impl RealDom { } /// Traverses the dom in a breadth first manner mutably, calling the provided function on each node. - pub fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(NodeMut)) { + pub fn traverse_breadth_first_mut( + &mut self, + enter_shadow_doms: bool, + mut f: impl FnMut(NodeMut), + ) { let mut queue = VecDeque::new(); queue.push_back(self.root_id()); while let Some(id) = queue.pop_front() { let tree = self.tree_ref(); - let children = tree.children_ids(id); + let children = tree.children_ids_advanced(id, enter_shadow_doms); drop(tree); if let Some(node) = self.get_mut(id) { f(node); diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 1f46216b2..1f26dc6a7 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -11,8 +11,6 @@ pub struct ShadowTree { pub shadow_roots: Vec, /// The node that children of the super tree should be inserted under. pub slot: Option, - /// The node in the super tree that the shadow_tree is attached to. - pub super_tree_root: NodeId, } /// A node in a tree. @@ -35,8 +33,43 @@ pub type TreeMutView<'a> = (EntitiesViewMut<'a>, ViewMut<'a, Node>); /// A immutable view of a tree. pub trait TreeRef { + /// Get the id of the parent of the current node, if enter_shadow_dom is true and the current node is a shadow root, the node the shadow root is attached to will be returned + #[inline] + fn parent_id_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Option { + // If this node is the root of a shadow_tree, return the node the shadow_tree is attached + let light_tree_root = self.light_tree_root(id); + match (light_tree_root, enter_shadow_dom) { + (Some(id), true) => Some(id), + _ => { + let parent_id = self.parent_id(id); + if enter_shadow_dom { + // If this node is attached via a slot, return the slot as the parent instead of the light tree parent + parent_id.map(|id| { + self.shadow_tree(id) + .and_then(|tree| tree.slot) + .unwrap_or(id) + }) + } else { + parent_id + } + } + } + } /// The parent id of the node. fn parent_id(&self, id: NodeId) -> Option; + /// Get the ids of the children of the current node, if enter_shadow_dom is true and the current node is a shadow slot, the ids of the nodes under the node the shadow slot is attached to will be returned + #[inline] + fn children_ids_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Vec { + let shadow_tree = self.shadow_tree(id); + let slot_of_light_tree = self.slot_for_light_tree(id); + match (shadow_tree, slot_of_light_tree, enter_shadow_dom) { + // If this node is a shadow root, return the shadow roots + (Some(tree), _, true) => tree.shadow_roots.clone(), + // If this node is a slot, return the children of the node the slot is attached to + (None, Some(id), true) => self.children_ids(id), + _ => self.children_ids(id), + } + } /// The children ids of the node. fn children_ids(&self, id: NodeId) -> Vec; /// The shadow tree tree under the node. @@ -229,7 +262,6 @@ impl<'a> TreeMut for TreeMutView<'a> { let light_root_height; { let shadow_tree = ShadowTree { - super_tree_root: id, shadow_roots: shadow_roots.clone(), slot, }; @@ -251,6 +283,7 @@ impl<'a> TreeMut for TreeMutView<'a> { // Now that we have created the shadow_tree, we need to update the height of the shadow_tree roots for root in shadow_roots { + (&mut self.1).get(root).unwrap().light_tree_root = Some(id); set_height(self, root, light_root_height + 1); } } @@ -319,7 +352,7 @@ fn set_height(tree: &mut TreeMutView<'_>, node: NodeId, height: u16) { if let Some(shadow_tree) = shadow_tree { // Set the height of the shadow_tree roots for &shadow_root in &shadow_tree.shadow_roots { - set_height(tree, shadow_root, height); + set_height(tree, shadow_root, height + 1); } } else { // Otherwise, we just set the height of the children to be one more than the height of the parent @@ -362,17 +395,17 @@ impl<'a> TreeRef for TreeMutView<'a> { fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree> { let node_data = &self.1; - node_data.get(id).unwrap().child_subtree.as_ref() + node_data.get(id).ok()?.child_subtree.as_ref() } fn slot_for_light_tree(&self, id: NodeId) -> Option { let node_data = &self.1; - node_data.get(id).unwrap().slot_for_light_tree + node_data.get(id).ok()?.slot_for_light_tree } fn light_tree_root(&self, id: NodeId) -> Option { let node_data = &self.1; - node_data.get(id).unwrap().light_tree_root + node_data.get(id).ok()?.light_tree_root } } diff --git a/packages/native-core/tests/called_minimally_on_build.rs b/packages/native-core/tests/called_minimally_on_build.rs index 394cf464a..f4e8cf6e1 100644 --- a/packages/native-core/tests/called_minimally_on_build.rs +++ b/packages/native-core/tests/called_minimally_on_build.rs @@ -146,7 +146,7 @@ macro_rules! test_state{ dioxus_state.apply_mutations(&mut dom, mutations); dom.update_state(SendAnyMap::new()); - dom.traverse_depth_first(|n| { + dom.traverse_depth_first(false, |n| { $( assert_eq!(n.get::<$state>().unwrap().0, 1); )* diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs index 3aa1b7462..b7c6e7c97 100644 --- a/packages/native-core/tests/custom_element.rs +++ b/packages/native-core/tests/custom_element.rs @@ -23,14 +23,26 @@ impl State for ColorState { fn update<'a>( &mut self, - _: NodeView, + view: NodeView, _: ::ElementBorrowed<'a>, parent: Option<::ElementBorrowed<'a>>, _: Vec<::ElementBorrowed<'a>>, _: &SendAnyMap, ) -> bool { - if let Some((parent,)) = parent { - self.color = parent.color; + if let Some(size) = view + .attributes() + .into_iter() + .flatten() + .find(|attr| attr.attribute.name == "color") + { + self.color = size + .value + .as_float() + .or_else(|| size.value.as_int().map(|i| i as f64)) + .or_else(|| size.value.as_text().and_then(|i| i.parse().ok())) + .unwrap_or(0.0) as usize; + } else if let Some((parent,)) = parent { + *self = *parent; } true } @@ -74,11 +86,6 @@ impl State for LayoutState { _: Vec<::ElementBorrowed<'a>>, _: &SendAnyMap, ) -> bool { - println!( - "Updating layout state @{:?} {:?}", - parent.as_ref().map(|(p,)| p.size), - view.node_id() - ); if let Some(size) = view .attributes() .into_iter() @@ -93,7 +100,7 @@ impl State for LayoutState { .unwrap_or(0.0) as usize; } else if let Some((parent,)) = parent { if parent.size > 0 { - self.size -= 1; + self.size = parent.size - 1; } } true @@ -130,7 +137,7 @@ mod dioxus_elements { $(#[$attr])* pub struct $name; - #[allow(non_upper_case_globals)] + #[allow(non_upper_case_globals, unused)] impl $name { pub const TAG_NAME: &'static str = stringify!($name); pub const NAME_SPACE: Option<&'static str> = None; @@ -152,10 +159,14 @@ mod dioxus_elements { builder_constructors! { customelementslot { size: attr, + color: attr, }; customelementnoslot { + size: attr, + color: attr, }; testing132 { + color: attr, }; } } @@ -253,6 +264,7 @@ fn custom_elements_work() { cx.render(rsx! { customelementslot { size: "{count}", + color: "1", customelementslot { testing132 {} } @@ -277,7 +289,7 @@ fn custom_elements_work() { let ctx = SendAnyMap::new(); rdom.update_state(ctx); - for _ in 0..10 { + for i in 0..10usize { dom.wait_for_work().await; let mutations = dom.render_immediate(); @@ -287,13 +299,33 @@ fn custom_elements_work() { rdom.update_state(ctx); // render... - rdom.traverse_depth_first(|node| { + rdom.traverse_depth_first(true, |node| { let node_type = &*node.node_type(); - let indent = " ".repeat(node.height() as usize); + let height = node.height() as usize; + let indent = " ".repeat(height); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); let id = node.id(); println!("{indent}{id:?} {color:?} {size:?} {node_type:?}"); + match node_type { + NodeType::Element(el) => { + match el.tag.as_str() { + // the color should bubble up from customelementslot + "testing132" | "customelementslot" => { + assert_eq!(color.color, 1); + } + // the color of the light dom should not effect the color of the shadow dom, so the color of divs in the shadow dom should be 0 + "div" => { + assert_eq!(color.color, 0); + } + _ => {} + } + if el.tag != "Root" { + assert_eq!(size.size, (i + 2).saturating_sub(height)); + } + } + _ => {} + } }); } }); From c2b873c650f68c8925cd01608af039de1c930cb0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 12 Apr 2023 11:39:57 -0500 Subject: [PATCH 434/895] restore core changes --- packages/core/src/scopes.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 5d1c661c0..5601d57fe 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -591,8 +591,6 @@ impl<'src> ScopeState { propagates: event.propagates, data, }); - } else { - println!("Failed to downcast event data") } })) }; From 2f3bb4d6d53dac31f0f86b61fb2c3110a93be2ba Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Wed, 12 Apr 2023 19:48:27 +0200 Subject: [PATCH 435/895] make clippy happy --- packages/router/src/components/link.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index 24374bda8..8471d95e4 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -185,10 +185,8 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { let do_default = onclick.is_none() || !onclick_only; let action = move |event| { - if do_default { - if is_router_nav { - let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); - } + if do_default && is_router_nav { + let _ = sender.unbounded_send(RouterMessage::Push(target.clone())); } if let Some(handler) = onclick { From 90c7e22f8b75e35d2cd9359dca0ac36acde25ea1 Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Wed, 12 Apr 2023 20:19:01 +0200 Subject: [PATCH 436/895] actually make clippy happy --- examples/crm.rs | 14 +++--- examples/flat_router.rs | 2 +- examples/link.rs | 2 +- examples/router.rs | 4 +- examples/simple_desktop.rs | 2 +- packages/router-core/src/service.rs | 62 ++++++++++++------------- packages/router-core/src/utils/route.rs | 4 +- packages/router/examples/simple.rs | 2 +- packages/router/tests/via_ssr/link.rs | 2 +- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/examples/crm.rs b/examples/crm.rs index e45cdfe6a..abdb72c4b 100644 --- a/examples/crm.rs +++ b/examples/crm.rs @@ -20,7 +20,7 @@ pub struct Client { type ClientContext = Arc>>; fn App(cx: Scope) -> Element { - use_router(cx, &|| RouterConfiguration::default(), &|| { + use_router(cx, &RouterConfiguration::default, &|| { Segment::content(comp(ClientList)) .fixed( "new", @@ -32,7 +32,7 @@ fn App(cx: Scope) -> Element { ) }); - use_context_provider::(&cx, Default::default); + use_context_provider::(cx, Default::default); render! { link { @@ -86,11 +86,11 @@ fn ClientList(cx: Scope) -> Element { struct ClientAddName; fn ClientAdd(cx: Scope) -> Element { let clients = use_context::(cx).unwrap(); - let first_name = use_state(&cx, String::new); - let last_name = use_state(&cx, String::new); - let description = use_state(&cx, String::new); + let first_name = use_state(cx, String::new); + let last_name = use_state(cx, String::new); + let description = use_state(cx, String::new); - let navigator = use_navigate(&cx).unwrap(); + let navigator = use_navigate(cx).unwrap(); cx.render(rsx! { h2 { "Add new Client" } @@ -178,7 +178,7 @@ fn ClientAdd(cx: Scope) -> Element { struct SettingsName; fn Settings(cx: Scope) -> Element { - let clients = use_context::(&cx).unwrap(); + let clients = use_context::(cx).unwrap(); cx.render(rsx! { h2 { "Settings" } diff --git a/examples/flat_router.rs b/examples/flat_router.rs index a0d1e3b7e..ab3f365dd 100644 --- a/examples/flat_router.rs +++ b/examples/flat_router.rs @@ -17,7 +17,7 @@ fn main() { } fn app(cx: Scope) -> Element { - use_router(cx, &|| RouterConfiguration::default(), &|| { + use_router(cx, &RouterConfiguration::default, &|| { Segment::content(comp(Home)) .fixed("games", comp(Games)) .fixed("play", comp(Play)) diff --git a/examples/link.rs b/examples/link.rs index b25ee11c3..b6dd43412 100644 --- a/examples/link.rs +++ b/examples/link.rs @@ -8,7 +8,7 @@ fn main() { } fn app(cx: Scope) -> Element { - use_router(cx, &|| RouterConfiguration::default(), &|| { + use_router(cx, &RouterConfiguration::default, &|| { Segment::content(comp(Home)).fixed("settings", comp(Settings)) }); diff --git a/examples/router.rs b/examples/router.rs index 46bce97d7..a71ca144f 100644 --- a/examples/router.rs +++ b/examples/router.rs @@ -8,7 +8,7 @@ fn main() { } fn app(cx: Scope) -> Element { - use_router(cx, &|| RouterConfiguration::default(), &|| { + use_router(cx, &RouterConfiguration::default, &|| { Segment::content(comp(Home)) .fixed( "users", @@ -79,7 +79,7 @@ fn User(cx: Scope) -> Element { let user = state.parameter::().unwrap(); - let query = state.query.as_ref().map(|q| q.clone()).unwrap_or_default(); + let query = state.query.as_ref().cloned().unwrap_or_default(); let bold = query.contains("bold") && !query.contains("bold=false"); cx.render(rsx! { diff --git a/examples/simple_desktop.rs b/examples/simple_desktop.rs index 35d101d83..aa6a505b6 100644 --- a/examples/simple_desktop.rs +++ b/examples/simple_desktop.rs @@ -14,7 +14,7 @@ fn main() { } fn app(cx: Scope) -> Element { - use_router(cx, &|| RouterConfiguration::default(), &|| { + use_router(cx, &RouterConfiguration::default, &|| { Segment::content(comp(Home)) .fixed( "blog", diff --git a/packages/router-core/src/service.rs b/packages/router-core/src/service.rs index 0860a50ca..8ef5ef49f 100644 --- a/packages/router-core/src/service.rs +++ b/packages/router-core/src/service.rs @@ -590,8 +590,8 @@ mod tests { assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); assert_eq!(state.query, Some(String::from("test=value"))); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); assert_eq!(s.names, state.name_map); } @@ -599,7 +599,7 @@ mod tests { fn update_routing_root_index() { let (mut s, _, _) = RouterService::<_, u8>::new( test_segment(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -619,8 +619,8 @@ mod tests { assert_eq!(state.path, String::from("/")); assert!(state.query.is_none()); assert!(state.prefix.is_none()); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -645,8 +645,8 @@ mod tests { }); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -699,7 +699,7 @@ mod tests { let (mut s, _, _) = RouterService::<_, u8>::new( Segment::empty(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(move |id| { ids2.lock().unwrap().push(id); }), @@ -727,7 +727,7 @@ mod tests { fn push_internal() { let (mut s, _, _) = RouterService::<_, u8>::new( test_segment(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -746,15 +746,15 @@ mod tests { }); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, true); - assert_eq!(state.can_go_forward, false); + assert!(state.can_go_back); + assert!(!state.can_go_forward); } #[test] fn push_named() { let (mut s, _, _) = RouterService::<_, u8>::new( test_segment(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -773,8 +773,8 @@ mod tests { }); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, true); - assert_eq!(state.can_go_forward, false); + assert!(state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -811,15 +811,15 @@ mod tests { r }); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] fn replace_named() { let (mut s, _, _) = RouterService::<_, u8>::new( test_segment(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -838,15 +838,15 @@ mod tests { }); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] fn replace_internal() { let (mut s, _, _) = RouterService::<_, u8>::new( test_segment(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -865,8 +865,8 @@ mod tests { }); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -903,15 +903,15 @@ mod tests { r }); assert_eq!(state.path, String::from("/fixed")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] fn subscribe() { let (mut s, _, _) = RouterService::<_, u8>::new( Segment::empty(), - Box::new(MemoryHistory::default()), + Box::::default(), Arc::new(|_| {}), None, ContentAtom("external target"), @@ -982,8 +982,8 @@ mod tests { r }); assert_eq!(state.path, String::from("/%F0%9F%A5%B3")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -1006,8 +1006,8 @@ mod tests { assert!(state.names.is_empty()); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/%F0%9F%8E%BA")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } #[test] @@ -1078,7 +1078,7 @@ mod tests { assert_eq!(state.path, String::from("/")); assert!(state.query.is_none()); assert_eq!(state.prefix, Some(String::from("/prefix"))); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, false); + assert!(!state.can_go_back); + assert!(!state.can_go_forward); } } diff --git a/packages/router-core/src/utils/route.rs b/packages/router-core/src/utils/route.rs index 130ac8336..30ab504d8 100644 --- a/packages/router-core/src/utils/route.rs +++ b/packages/router-core/src/utils/route.rs @@ -252,8 +252,8 @@ mod tests { assert!(state.names.is_empty()); assert!(state.parameters.is_empty()); assert_eq!(state.path, String::from("/")); - assert_eq!(state.can_go_back, false); - assert_eq!(state.can_go_forward, true); + assert!(!state.can_go_back); + assert!(state.can_go_forward); } #[test] diff --git a/packages/router/examples/simple.rs b/packages/router/examples/simple.rs index d7e572271..8357933dd 100644 --- a/packages/router/examples/simple.rs +++ b/packages/router/examples/simple.rs @@ -12,7 +12,7 @@ fn main() { fn App(cx: Scope) -> Element { use_router( - &cx, + cx, &|| { #[cfg(not(feature = "web"))] let history = MemoryHistory::default(); diff --git a/packages/router/tests/via_ssr/link.rs b/packages/router/tests/via_ssr/link.rs index 49eb5c327..afa4acf8e 100644 --- a/packages/router/tests/via_ssr/link.rs +++ b/packages/router/tests/via_ssr/link.rs @@ -14,7 +14,7 @@ fn prepare(link: Component) -> String { } impl PartialEq for AppProps { - fn eq(&self, other: &Self) -> bool { + fn eq(&self, _other: &Self) -> bool { false } } From efa73057949afc1ca809d7072864062fd61d63fd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 13 Apr 2023 10:29:38 -0500 Subject: [PATCH 437/895] Port widgets to the new system --- packages/native-core/src/custom_element.rs | 33 ++++---- packages/native-core/src/real_dom.rs | 24 +++++- packages/native-core/tests/custom_element.rs | 6 +- packages/rink/examples/widgets.rs | 2 +- packages/rink/src/focus.rs | 4 +- packages/rink/src/hooks.rs | 42 +++------- packages/rink/src/layout.rs | 9 +-- packages/rink/src/lib.rs | 51 ++++++++++--- packages/rink/src/query.rs | 19 +---- packages/rink/src/render.rs | 7 +- packages/rink/src/widgets/button.rs | 42 +++++----- packages/rink/src/widgets/checkbox.rs | 27 ++++--- packages/rink/src/widgets/input.rs | 43 ++++++++--- packages/rink/src/widgets/mod.rs | 80 ++++++++++++++------ packages/rink/src/widgets/number.rs | 36 ++++----- packages/rink/src/widgets/password.rs | 36 ++++----- packages/rink/src/widgets/slider.rs | 28 ++++--- packages/rink/src/widgets/textbox.rs | 37 ++++----- 18 files changed, 286 insertions(+), 240 deletions(-) diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs index 62d7e5368..675e928f1 100644 --- a/packages/native-core/src/custom_element.rs +++ b/packages/native-core/src/custom_element.rs @@ -9,7 +9,7 @@ use shipyard::Component; use crate::{ node::{FromAnyValue, NodeType}, node_ref::AttributeMask, - prelude::{NodeImmutable, NodeMut, RealDom}, + prelude::{NodeImmutable, NodeMut}, tree::TreeMut, NodeId, }; @@ -27,11 +27,15 @@ impl Default for CustomElementRegistry { } impl CustomElementRegistry { - pub fn register>(&mut self) { + pub fn register(&mut self) + where + F: CustomElementFactory, + U: CustomElementUpdater, + { self.builders.insert( - (W::NAME, W::NAMESPACE), + (F::NAME, F::NAMESPACE), CustomElementBuilder { - create: |dom| Box::new(W::create(dom)), + create: |node| Box::new(F::create(node)), }, ); } @@ -44,10 +48,7 @@ impl CustomElementRegistry { }; if let Some((tag, ns)) = element_tag { if let Some(builder) = self.builders.get(&(tag.as_str(), ns.as_deref())) { - let boxed_widget = { - let dom = node.real_dom_mut(); - (builder.create)(dom) - }; + let boxed_widget = { (builder.create)(node.reborrow()) }; let shadow_roots = boxed_widget.roots(); @@ -69,7 +70,7 @@ impl CustomElementRegistry { } struct CustomElementBuilder { - create: fn(&mut RealDom) -> Box>, + create: fn(NodeMut) -> Box>, } /// A controlled element that renders to a shadow DOM @@ -81,7 +82,7 @@ pub trait CustomElement: Send + Sync + 'stat const NAMESPACE: Option<&'static str> = None; /// Create a new widget *without mounting* it. - fn create(dom: &mut RealDom) -> Self; + fn create(node: NodeMut) -> Self; /// The root node of the widget. This must be static once the element is created. fn roots(&self) -> Vec; @@ -96,7 +97,7 @@ pub trait CustomElement: Send + Sync + 'stat } /// A factory for creating widgets -trait ElementFactory, V: FromAnyValue + Send + Sync = ()>: +pub trait CustomElementFactory, V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static { /// The tag the widget is registered under. @@ -106,21 +107,21 @@ trait ElementFactory, V: FromAnyValue + Send + Sync = const NAMESPACE: Option<&'static str> = None; /// Create a new widget. - fn create(dom: &mut RealDom) -> W; + fn create(dom: NodeMut) -> W; } -impl, V: FromAnyValue + Send + Sync> ElementFactory for W { +impl, V: FromAnyValue + Send + Sync> CustomElementFactory for W { const NAME: &'static str = W::NAME; const NAMESPACE: Option<&'static str> = W::NAMESPACE; - fn create(dom: &mut RealDom) -> Self { - Self::create(dom) + fn create(node: NodeMut) -> Self { + Self::create(node) } } /// A trait for updating widgets -trait CustomElementUpdater: Send + Sync + 'static { +pub trait CustomElementUpdater: Send + Sync + 'static { /// Called when the attributes of the widget are changed. fn attributes_changed(&mut self, light_root: NodeMut, attributes: &AttributeMask); diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index e885963d1..61e9644a3 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -10,7 +10,10 @@ use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; -use crate::custom_element::{CustomElement, CustomElementManager, CustomElementRegistry}; +use crate::custom_element::{ + CustomElement, CustomElementFactory, CustomElementManager, CustomElementRegistry, + CustomElementUpdater, +}; use crate::node::{ ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, TextNode, }; @@ -478,7 +481,16 @@ impl RealDom { /// Registers a new custom element. pub fn register_custom_element>(&mut self) { - self.custom_elements.write().unwrap().register::() + self.register_custom_element_factory::() + } + + /// Registers a new custom element with a custom factory. + pub fn register_custom_element_factory(&mut self) + where + F: CustomElementFactory, + U: CustomElementUpdater, + { + self.custom_elements.write().unwrap().register::() } } @@ -678,6 +690,14 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable for NodeMut<'a, V> { } impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { + /// Reborrow the node mutably + pub fn reborrow(&mut self) -> NodeMut<'_, V> { + NodeMut { + id: self.id, + dom: self.dom, + } + } + /// Get the real dom this node was created in mutably #[inline(always)] pub fn real_dom_mut(&mut self) -> &mut RealDom { diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs index b7c6e7c97..7bddeacc9 100644 --- a/packages/native-core/tests/custom_element.rs +++ b/packages/native-core/tests/custom_element.rs @@ -179,7 +179,8 @@ struct CustomElementWithSlot { impl CustomElement for CustomElementWithSlot { const NAME: &'static str = "customelementslot"; - fn create(dom: &mut RealDom<()>) -> Self { + fn create(mut node: NodeMut<()>) -> Self { + let dom = node.real_dom_mut(); let child = dom.create_node(ElementNode { tag: "div".into(), namespace: None, @@ -227,7 +228,8 @@ struct CustomElementWithNoSlot { impl CustomElement for CustomElementWithNoSlot { const NAME: &'static str = "customelementnoslot"; - fn create(dom: &mut RealDom<()>) -> Self { + fn create(mut node: NodeMut<()>) -> Self { + let dom = node.real_dom_mut(); let root = dom.create_node(ElementNode { tag: "div".into(), namespace: None, diff --git a/packages/rink/examples/widgets.rs b/packages/rink/examples/widgets.rs index 3e709313f..1226d5c3d 100644 --- a/packages/rink/examples/widgets.rs +++ b/packages/rink/examples/widgets.rs @@ -77,7 +77,7 @@ impl Driver for Counter { _: bool, ) { match event_type { - "oninput" => { + "input" => { // when the button is clicked, increment the counter if let EventData::Form(input_event) = &*event { if let Ok(value) = input_event.value.parse::() { diff --git a/packages/rink/src/focus.rs b/packages/rink/src/focus.rs index e26f79b3d..4ede95485 100644 --- a/packages/rink/src/focus.rs +++ b/packages/rink/src/focus.rs @@ -183,7 +183,7 @@ impl FocusState { if forward { // find the closest focusable element after the current level - rdom.traverse_depth_first(|n| { + rdom.traverse_depth_first(true, |n| { let node_level = n.get::().unwrap().level; if node_level != *focus_level && node_level.focusable() @@ -200,7 +200,7 @@ impl FocusState { }); } else { // find the closest focusable element before the current level - rdom.traverse_depth_first(|n| { + rdom.traverse_depth_first(true, |n| { let node_level = n.get::().unwrap().level; if node_level != *focus_level && node_level.focusable() diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index 341ab02ac..b54cc2eaf 100644 --- a/packages/rink/src/hooks.rs +++ b/packages/rink/src/hooks.rs @@ -25,7 +25,7 @@ use taffy::{prelude::Layout, Taffy}; use crate::focus::{Focus, Focused}; use crate::layout::TaffyLayout; -use crate::{layout_to_screen_space, FocusState}; +use crate::{get_abs_layout, layout_to_screen_space, FocusState}; #[derive(Debug, Clone, PartialEq)] pub struct Event { @@ -323,7 +323,7 @@ impl InnerInputState { if old_pos != Some(new_pos) { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mousemove") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let previously_contained = old_pos .filter(|pos| layout_contains_point(&node_layout, *pos)) .is_some(); @@ -347,7 +347,7 @@ impl InnerInputState { // mouseenter let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseenter") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let previously_contained = old_pos .filter(|pos| layout_contains_point(&node_layout, *pos)) .is_some(); @@ -370,7 +370,7 @@ impl InnerInputState { // mouseover let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseover") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let previously_contained = old_pos .filter(|pos| layout_contains_point(&node_layout, *pos)) .is_some(); @@ -393,7 +393,7 @@ impl InnerInputState { if was_pressed { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mousedown") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let currently_contains = layout_contains_point(&node_layout, new_pos); if currently_contains { @@ -414,7 +414,7 @@ impl InnerInputState { if was_released { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseup") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let currently_contains = layout_contains_point(&node_layout, new_pos); if currently_contains { @@ -436,7 +436,7 @@ impl InnerInputState { if mouse_data.trigger_button() == Some(DioxusMouseButton::Primary) && was_released { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("click") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let currently_contains = layout_contains_point(&node_layout, new_pos); if currently_contains { @@ -459,7 +459,7 @@ impl InnerInputState { { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("contextmenu") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let currently_contains = layout_contains_point(&node_layout, new_pos); if currently_contains { @@ -482,7 +482,7 @@ impl InnerInputState { if was_scrolled { let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("wheel") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let currently_contains = layout_contains_point(&node_layout, new_pos); @@ -505,7 +505,7 @@ impl InnerInputState { // mouseleave let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseleave") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let previously_contained = old_pos .filter(|pos| layout_contains_point(&node_layout, *pos)) .is_some(); @@ -528,7 +528,7 @@ impl InnerInputState { // mouseout let mut will_bubble = FxHashSet::default(); for node in dom.get_listening_sorted("mouseout") { - let node_layout = get_abs_layout(node, dom, layout); + let node_layout = get_abs_layout(node, layout); let previously_contained = old_pos .filter(|pos| layout_contains_point(&node_layout, *pos)) .is_some(); @@ -550,7 +550,7 @@ impl InnerInputState { // update focus if was_released { let mut focus_id = None; - dom.traverse_depth_first(|node| { + dom.traverse_depth_first(true, |node| { let node_layout = layout .layout(node.get::().unwrap().node.unwrap()) .unwrap(); @@ -572,24 +572,6 @@ impl InnerInputState { // } } -fn get_abs_layout(node: NodeRef, dom: &RealDom, taffy: &Taffy) -> Layout { - let mut node_layout = *taffy - .layout(node.get::().unwrap().node.unwrap()) - .unwrap(); - let mut current = node; - - while let Some(parent) = current.parent_id() { - let parent = dom.get(parent).unwrap(); - current = parent; - let parent_layout = taffy - .layout(parent.get::().unwrap().node.unwrap()) - .unwrap(); - node_layout.location.x += parent_layout.location.x; - node_layout.location.y += parent_layout.location.y; - } - node_layout -} - pub struct RinkInputHandler { state: Rc>, queued_events: Rc>>, diff --git a/packages/rink/src/layout.rs b/packages/rink/src/layout.rs index b7eff57a6..3bb087596 100644 --- a/packages/rink/src/layout.rs +++ b/packages/rink/src/layout.rs @@ -25,12 +25,6 @@ impl PossiblyUninitalized { _ => panic!("uninitalized"), } } - pub fn ok(self) -> Option { - match self { - Self::Initialized(i) => Some(i), - _ => None, - } - } } impl Default for PossiblyUninitalized { fn default() -> Self { @@ -54,6 +48,9 @@ impl State for TaffyLayout { .with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS)) .with_text(); + // The layout state should be effected by the shadow dom + const TRAVERSE_SHADOW_DOM: bool = true; + fn update<'a>( &mut self, node_view: NodeView, diff --git a/packages/rink/src/lib.rs b/packages/rink/src/lib.rs index 2aab01664..18b1e62c7 100644 --- a/packages/rink/src/lib.rs +++ b/packages/rink/src/lib.rs @@ -6,7 +6,7 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use dioxus_native_core::prelude::*; +use dioxus_native_core::{prelude::*, tree::TreeRef}; use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap}; use focus::FocusState; use futures::{channel::mpsc::UnboundedSender, pin_mut, Future, StreamExt}; @@ -262,7 +262,7 @@ pub fn render( } }, Some(evt) = event_reciever.next() => { - event_recieved=Some(evt); + event_recieved = Some(evt); } } } @@ -342,19 +342,50 @@ pub trait Driver { /// Before sending the event to drivers, we need to bubble it up the tree to any widgets that are listening fn bubble_event_to_widgets(rdom: &mut RealDom, event: &Event) { let id = event.id; - let mut node = Some(rdom.get_mut(id).unwrap()); + let mut node = Some(id); + + while let Some(node_id) = node { + let parent_id = { + let tree = rdom.tree_ref(); + tree.parent_id_advanced(node_id, true) + }; - while let Some(mut node_mut) = node { - let parent_id = node_mut.parent_id(); - if let Some(mut widget) = node_mut - .get_mut::() - .map(|w| w.clone()) { - widget.handle_event(event, &mut node_mut) + // println!("@ bubbling event to node {:?}", node_id); + let mut node_mut = rdom.get_mut(node_id).unwrap(); + if let Some(mut widget) = node_mut + .get_mut::() + .map(|w| w.clone()) + { + widget.handle_event(event, node_mut) + } } + if !event.bubbles { + // println!("event does not bubble"); break; } - node = parent_id.map(|id| rdom.get_mut(id).unwrap()); + node = parent_id; } } + +pub(crate) fn get_abs_layout(node: NodeRef, taffy: &Taffy) -> Layout { + let mut node_layout = *taffy + .layout(node.get::().unwrap().node.unwrap()) + .unwrap(); + let mut current = node; + + let dom = node.real_dom(); + let tree = dom.tree_ref(); + + while let Some(parent) = tree.parent_id_advanced(current.id(), true) { + let parent = dom.get(parent).unwrap(); + current = parent; + let parent_layout = taffy + .layout(parent.get::().unwrap().node.unwrap()) + .unwrap(); + node_layout.location.x += parent_layout.location.x; + node_layout.location.y += parent_layout.location.y; + } + node_layout +} diff --git a/packages/rink/src/query.rs b/packages/rink/src/query.rs index c204e1953..3b8f319cf 100644 --- a/packages/rink/src/query.rs +++ b/packages/rink/src/query.rs @@ -8,7 +8,7 @@ use taffy::{ Taffy, }; -use crate::{layout::TaffyLayout, layout_to_screen_space}; +use crate::{get_abs_layout, layout_to_screen_space}; /// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered. /// Provided as a root context for all tui applictions. @@ -95,21 +95,8 @@ impl<'a> ElementRef<'a> { } pub(crate) fn get_layout(node: NodeRef, stretch: &Taffy) -> Option { - let layout = stretch - .layout(node.get::().unwrap().node.ok()?) - .ok()?; - - let mut current_node_id = node.parent_id(); - let mut pos = layout.location; - let rdom = node.real_dom(); - while let Some(node) = current_node_id.and_then(|id| rdom.get(id)) { - let current_layout = stretch - .layout(node.get::().unwrap().node.ok()?) - .ok()?; - pos.x += current_layout.location.x; - pos.y += current_layout.location.y; - current_node_id = node.parent_id(); - } + let layout = get_abs_layout(node, stretch); + let pos = layout.location; Some(Layout { order: layout.order, diff --git a/packages/rink/src/render.rs b/packages/rink/src/render.rs index ef433976d..19d642720 100644 --- a/packages/rink/src/render.rs +++ b/packages/rink/src/render.rs @@ -1,4 +1,4 @@ -use dioxus_native_core::prelude::*; +use dioxus_native_core::{prelude::*, tree::TreeRef}; use std::io::Stdout; use taffy::{ geometry::Point, @@ -83,7 +83,10 @@ pub(crate) fn render_vnode( frame.render_widget(WidgetWithContext::new(node, cfg), area); } - for c in node.children() { + let node_id = node.id(); + let rdom = node.real_dom(); + for child_id in rdom.tree_ref().children_ids_advanced(node_id, true) { + let c = rdom.get(child_id).unwrap(); render_vnode(frame, layout, c, cfg, location); } } diff --git a/packages/rink/src/widgets/button.rs b/packages/rink/src/widgets/button.rs index 2eaddfe59..e4d3754f1 100644 --- a/packages/rink/src/widgets/button.rs +++ b/packages/rink/src/widgets/button.rs @@ -2,14 +2,14 @@ use std::collections::HashMap; use dioxus_html::input_data::keyboard_types::Key; use dioxus_native_core::{ + custom_element::CustomElement, node::OwnedAttributeDiscription, node_ref::AttributeMask, prelude::NodeType, - real_dom::{ElementNodeMut, NodeImmutable, NodeTypeMut, RealDom}, - utils::widget_watcher::Widget, + real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, NodeId, }; -use shipyard::UniqueViewMut; +use shipyard::UniqueView; use crate::FormData; @@ -17,7 +17,6 @@ use super::{RinkWidget, WidgetContext}; #[derive(Debug, Default)] pub(crate) struct Button { - div_id: NodeId, text_id: NodeId, value: String, } @@ -88,14 +87,14 @@ impl Button { } } - fn switch(&mut self, ctx: &mut WidgetContext) { + fn switch(&mut self, ctx: &mut WidgetContext, node: NodeMut) { let data = FormData { value: self.value.to_string(), values: HashMap::new(), files: None, }; ctx.send(crate::Event { - id: self.div_id, + id: node.id(), name: "input", data: crate::EventData::Form(data), bubbles: true, @@ -103,10 +102,14 @@ impl Button { } } -impl Widget for Button { +impl CustomElement for Button { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.text_id] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -127,11 +130,8 @@ impl Widget for Button { root.add_event_listener("keydown"); root.add_event_listener("click"); - let div_id = root.id(); - root.add_child(text_id); Self { - div_id, text_id, value: value.unwrap_or_default(), } @@ -139,7 +139,7 @@ impl Widget for Button { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -175,16 +175,18 @@ impl RinkWidget for Button { fn handle_event( &mut self, event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, + mut node: dioxus_native_core::real_dom::NodeMut, ) { - let mut ctx: UniqueViewMut = node - .real_dom_mut() - .raw_world_mut() - .borrow() - .expect("expected widget context"); + let mut ctx: WidgetContext = { + node.real_dom_mut() + .raw_world_mut() + .borrow::>() + .expect("expected widget context") + .clone() + }; match event.name { - "click" => self.switch(&mut ctx), + "click" => self.switch(&mut ctx, node), "keydown" => { if let crate::EventData::Keyboard(data) = &event.data { if !data.is_auto_repeating() @@ -194,7 +196,7 @@ impl RinkWidget for Button { _ => false, } { - self.switch(&mut ctx); + self.switch(&mut ctx, node); } } } diff --git a/packages/rink/src/widgets/checkbox.rs b/packages/rink/src/widgets/checkbox.rs index 943db5213..24b3f6244 100644 --- a/packages/rink/src/widgets/checkbox.rs +++ b/packages/rink/src/widgets/checkbox.rs @@ -2,11 +2,11 @@ use std::collections::HashMap; use dioxus_html::input_data::keyboard_types::Key; use dioxus_native_core::{ + custom_element::CustomElement, node::OwnedAttributeDiscription, node_ref::AttributeMask, prelude::NodeType, real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut}, - utils::widget_watcher::Widget, NodeId, }; use shipyard::UniqueView; @@ -91,7 +91,7 @@ impl CheckBox { == "true"; } - fn write_value(&self, root: &mut NodeMut) { + fn write_value(&self, mut root: NodeMut) { let single_char = { let node_type = root.node_type_mut(); let NodeTypeMut::Element( el) = node_type else { panic!("input must be an element") }; @@ -117,7 +117,7 @@ impl CheckBox { } } - fn switch(&mut self, node: &mut NodeMut) { + fn switch(&mut self, mut node: NodeMut) { let new_state = !self.checked; let data = FormData { @@ -147,10 +147,14 @@ impl CheckBox { } } -impl Widget for CheckBox { +impl CustomElement for CheckBox { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.text_id] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -172,7 +176,6 @@ impl Widget for CheckBox { root.add_event_listener("click"); root.add_event_listener("keydown"); let div_id = root.id(); - root.add_child(text_id); let myself = Self { div_id, @@ -187,7 +190,7 @@ impl Widget for CheckBox { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -199,7 +202,7 @@ impl Widget for CheckBox { self.update_size_attr(&mut el); self.update_checked_attr(&el); } - self.write_value(&mut root); + self.write_value(root); } AttributeMask::Some(attrs) => { { @@ -216,7 +219,7 @@ impl Widget for CheckBox { } } if attrs.contains("checked") { - self.write_value(&mut root); + self.write_value(root); } } } @@ -224,11 +227,7 @@ impl Widget for CheckBox { } impl RinkWidget for CheckBox { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { match event.name { "click" => self.switch(node), "keydown" => { diff --git a/packages/rink/src/widgets/input.rs b/packages/rink/src/widgets/input.rs index 2253ae096..c6a3e56b9 100644 --- a/packages/rink/src/widgets/input.rs +++ b/packages/rink/src/widgets/input.rs @@ -1,6 +1,6 @@ use dioxus_native_core::{ - node::OwnedAttributeDiscription, prelude::NodeType, real_dom::NodeImmutable, - utils::widget_watcher::Widget, + custom_element::CustomElement, node::OwnedAttributeDiscription, prelude::NodeType, + real_dom::NodeImmutable, }; use super::{ @@ -18,10 +18,32 @@ pub(crate) enum Input { Slider(Slider), } -impl Widget for Input { +impl CustomElement for Input { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + match self { + Input::Button(button) => button.roots(), + Input::CheckBox(checkbox) => checkbox.roots(), + Input::TextBox(textbox) => textbox.roots(), + Input::Password(password) => password.roots(), + Input::Number(number) => number.roots(), + Input::Slider(slider) => slider.roots(), + } + } + + fn slot(&self) -> Option { + match self { + Input::Button(button) => button.slot(), + Input::CheckBox(checkbox) => checkbox.slot(), + Input::TextBox(textbox) => textbox.slot(), + Input::Password(password) => password.slot(), + Input::Number(number) => number.slot(), + Input::Slider(slider) => slider.slot(), + } + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { { // currently widgets are not allowed to have children let children = root.child_ids(); @@ -42,7 +64,10 @@ impl Widget for Input { namespace: None, }) .and_then(|value| value.as_text()); - match input_type { + match input_type + .map(|type_| type_.trim().to_lowercase()) + .as_deref() + { Some("button") => { drop(node_type); Input::Button(Button::create(root)) @@ -76,7 +101,7 @@ impl Widget for Input { fn attributes_changed( &mut self, - root: dioxus_native_core::real_dom::NodeMut<()>, + root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match self { @@ -103,11 +128,7 @@ impl Widget for Input { } impl RinkWidget for Input { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { match self { Input::Button(button) => { button.handle_event(event, node); diff --git a/packages/rink/src/widgets/mod.rs b/packages/rink/src/widgets/mod.rs index 283ebbcd9..27dea751d 100644 --- a/packages/rink/src/widgets/mod.rs +++ b/packages/rink/src/widgets/mod.rs @@ -9,8 +9,8 @@ mod textbox; use std::sync::{Arc, RwLock}; use dioxus_native_core::{ - real_dom::RealDom, - utils::widget_watcher::{Widget, WidgetFactory, WidgetUpdater, WidgetWatcher}, + custom_element::{CustomElement, CustomElementUpdater}, + real_dom::{NodeMut, RealDom}, }; use futures_channel::mpsc::UnboundedSender; use shipyard::{Component, Unique}; @@ -21,42 +21,64 @@ pub(crate) fn register_widgets(rdom: &mut RealDom, sender: UnboundedSender, RinkWidgetTraitObject>(); - - widget_watcher.attach(rdom); + rdom.register_custom_element::>(); } -trait RinkWidget: Sync + Send + Widget + 'static { - fn handle_event(&mut self, event: &Event, node: &mut dioxus_native_core::real_dom::NodeMut); +trait RinkWidget: Sync + Send + CustomElement + 'static { + fn handle_event(&mut self, event: &Event, node: dioxus_native_core::real_dom::NodeMut); } -pub trait RinkWidgetResponder: WidgetUpdater { - fn handle_event(&mut self, event: &Event, node: &mut dioxus_native_core::real_dom::NodeMut); +pub trait RinkWidgetResponder: CustomElementUpdater { + fn handle_event(&mut self, event: &Event, node: dioxus_native_core::real_dom::NodeMut); } impl RinkWidgetResponder for W { - fn handle_event(&mut self, event: &Event, node: &mut dioxus_native_core::real_dom::NodeMut) { + fn handle_event(&mut self, event: &Event, node: dioxus_native_core::real_dom::NodeMut) { RinkWidget::handle_event(self, event, node) } } -struct RinkWidgetTraitObjectFactory { +struct RinkWidgetWrapper { + inner: RinkWidgetTraitObject, _marker: std::marker::PhantomData, } -impl WidgetFactory for RinkWidgetTraitObjectFactory { +impl CustomElement for RinkWidgetWrapper { const NAME: &'static str = W::NAME; - fn create(node: &mut dioxus_native_core::real_dom::NodeMut) -> RinkWidgetTraitObject { + const NAMESPACE: Option<&'static str> = W::NAMESPACE; + + fn create(mut node: NodeMut) -> Self { let myself = RinkWidgetTraitObject { - widget: Arc::new(RwLock::new(W::create(node))), + widget: Arc::new(RwLock::new(W::create(node.reborrow()))), }; + + // Insert the widget as an arbitrary data node so that it can be recognized when bubbling events node.insert(myself.clone()); - myself + + RinkWidgetWrapper { + inner: myself, + _marker: std::marker::PhantomData, + } + } + + fn attributes_changed( + &mut self, + root: dioxus_native_core::real_dom::NodeMut, + attributes: &dioxus_native_core::node_ref::AttributeMask, + ) { + let mut widget = self.inner.widget.write().unwrap(); + widget.attributes_changed(root, attributes); + } + + fn roots(&self) -> Vec { + let widget = self.inner.widget.read().unwrap(); + widget.roots() + } + + fn slot(&self) -> Option { + let widget = self.inner.widget.read().unwrap(); + widget.slot() } } @@ -65,25 +87,35 @@ pub(crate) struct RinkWidgetTraitObject { widget: Arc>, } -impl WidgetUpdater for RinkWidgetTraitObject { +impl CustomElementUpdater for RinkWidgetTraitObject { fn attributes_changed( &mut self, - root: dioxus_native_core::real_dom::NodeMut, + light_root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { let mut widget = self.widget.write().unwrap(); - widget.attributes_changed(root, attributes); + widget.attributes_changed(light_root, attributes); + } + + fn roots(&self) -> Vec { + let widget = self.widget.read().unwrap(); + widget.roots() + } + + fn slot(&self) -> Option { + let widget = self.widget.read().unwrap(); + widget.slot() } } impl RinkWidgetResponder for RinkWidgetTraitObject { - fn handle_event(&mut self, event: &Event, node: &mut dioxus_native_core::real_dom::NodeMut) { + fn handle_event(&mut self, event: &Event, node: dioxus_native_core::real_dom::NodeMut) { let mut widget = self.widget.write().unwrap(); widget.handle_event(event, node); } } -#[derive(Unique)] +#[derive(Unique, Clone)] pub(crate) struct WidgetContext { sender: UnboundedSender, } diff --git a/packages/rink/src/widgets/number.rs b/packages/rink/src/widgets/number.rs index 2925e2966..c83d514b5 100644 --- a/packages/rink/src/widgets/number.rs +++ b/packages/rink/src/widgets/number.rs @@ -3,14 +3,12 @@ use std::{collections::HashMap, io::stdout}; use crossterm::{cursor::MoveTo, execute}; use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; use dioxus_native_core::{ + custom_element::CustomElement, node::OwnedAttributeDiscription, node_ref::AttributeMask, prelude::{ElementNode, NodeType}, real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::{ - cursor::{Cursor, Pos}, - widget_watcher::Widget, - }, + utils::cursor::{Cursor, Pos}, NodeId, }; use shipyard::UniqueView; @@ -169,7 +167,7 @@ impl Number { self.text = (num - 1.0).to_string(); } - fn handle_keydown(&mut self, root: &mut NodeMut, data: &KeyboardData) { + fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { let key = data.key(); let is_text = match key.clone() { Key::ArrowLeft | Key::ArrowRight | Key::Backspace => true, @@ -235,14 +233,11 @@ impl Number { } } - fn handle_mousemove(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { if self.dragging { let id = root.id(); let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } // textboxs are only one line tall new.row = 0; @@ -254,12 +249,9 @@ impl Number { } } - fn handle_mousedown(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } // textboxs are only one line tall new.row = 0; @@ -297,10 +289,14 @@ impl Number { } } -impl Widget for Number { +impl CustomElement for Number { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.div_wrapper] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -364,8 +360,6 @@ impl Widget for Number { root.add_event_listener("keydown"); root.add_event_listener("focusout"); - root.add_child(div_wrapper_id); - Self { pre_cursor_text: pre_text_id, highlighted_text: highlighted_text_id, @@ -379,7 +373,7 @@ impl Widget for Number { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -418,11 +412,7 @@ impl Widget for Number { } impl RinkWidget for Number { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { match event.name { "keydown" => { if let EventData::Keyboard(data) = &event.data { diff --git a/packages/rink/src/widgets/password.rs b/packages/rink/src/widgets/password.rs index 483b1e175..7e570a631 100644 --- a/packages/rink/src/widgets/password.rs +++ b/packages/rink/src/widgets/password.rs @@ -3,14 +3,12 @@ use std::{collections::HashMap, io::stdout}; use crossterm::{cursor::MoveTo, execute}; use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; use dioxus_native_core::{ + custom_element::CustomElement, node::OwnedAttributeDiscription, node_ref::AttributeMask, prelude::{ElementNode, NodeType}, real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::{ - cursor::{Cursor, Pos}, - widget_watcher::Widget, - }, + utils::cursor::{Cursor, Pos}, NodeId, }; use shipyard::UniqueView; @@ -159,7 +157,7 @@ impl Password { } } - fn handle_keydown(&mut self, root: &mut NodeMut, data: &KeyboardData) { + fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { let key = data.key(); let modifiers = data.modifiers(); let code = data.code(); @@ -203,14 +201,11 @@ impl Password { } } - fn handle_mousemove(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { if self.dragging { let id = root.id(); let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } // textboxs are only one line tall new.row = 0; @@ -222,12 +217,9 @@ impl Password { } } - fn handle_mousedown(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } // textboxs are only one line tall new.row = 0; @@ -265,10 +257,14 @@ impl Password { } } -impl Widget for Password { +impl CustomElement for Password { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.div_wrapper] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -332,8 +328,6 @@ impl Widget for Password { root.add_event_listener("keydown"); root.add_event_listener("focusout"); - root.add_child(div_wrapper_id); - Self { pre_cursor_text: pre_text_id, highlighted_text: highlighted_text_id, @@ -347,7 +341,7 @@ impl Widget for Password { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -386,11 +380,7 @@ impl Widget for Password { } impl RinkWidget for Password { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { match event.name { "keydown" => { if let EventData::Keyboard(data) = &event.data { diff --git a/packages/rink/src/widgets/slider.rs b/packages/rink/src/widgets/slider.rs index e1fa4f980..f97c12bf6 100644 --- a/packages/rink/src/widgets/slider.rs +++ b/packages/rink/src/widgets/slider.rs @@ -2,11 +2,11 @@ use std::collections::HashMap; use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; use dioxus_native_core::{ + custom_element::CustomElement, node::{OwnedAttributeDiscription, OwnedAttributeValue}, node_ref::AttributeMask, prelude::{ElementNode, NodeType}, real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::widget_watcher::Widget, NodeId, }; use shipyard::UniqueView; @@ -205,7 +205,7 @@ impl Slider { } } - fn handle_keydown(&mut self, root: &mut NodeMut, data: &KeyboardData) { + fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { let key = data.key(); let step = self.step(); @@ -227,7 +227,7 @@ impl Slider { self.write_value(rdom, id); } - fn handle_mousemove(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { if !data.held_buttons().is_empty() { let id = root.id(); let rdom = root.real_dom_mut(); @@ -250,10 +250,14 @@ impl Slider { } } -impl Widget for Slider { +impl CustomElement for Slider { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.div_wrapper] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -364,12 +368,10 @@ impl Widget for Slider { div_wrapper.add_child(cursor_span_id); div_wrapper.add_child(post_cursor_div_id); - div_wrapper.add_event_listener("mousemove"); - div_wrapper.add_event_listener("mousedown"); + root.add_event_listener("mousemove"); + root.add_event_listener("mousedown"); root.add_event_listener("keydown"); - root.add_child(div_wrapper_id); - Self { pre_cursor_div: pre_cursor_div_id, post_cursor_div: post_cursor_div_id, @@ -381,7 +383,7 @@ impl Widget for Slider { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -428,11 +430,7 @@ impl Widget for Slider { } impl RinkWidget for Slider { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { match event.name { "keydown" => { if let EventData::Keyboard(data) = &event.data { diff --git a/packages/rink/src/widgets/textbox.rs b/packages/rink/src/widgets/textbox.rs index 16f73fd78..8eaadb7a7 100644 --- a/packages/rink/src/widgets/textbox.rs +++ b/packages/rink/src/widgets/textbox.rs @@ -3,14 +3,12 @@ use std::{collections::HashMap, io::stdout}; use crossterm::{cursor::MoveTo, execute}; use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; use dioxus_native_core::{ + custom_element::CustomElement, node::OwnedAttributeDiscription, node_ref::AttributeMask, prelude::{ElementNode, NodeType}, real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::{ - cursor::{Cursor, Pos}, - widget_watcher::Widget, - }, + utils::cursor::{Cursor, Pos}, NodeId, }; use shipyard::UniqueView; @@ -159,7 +157,7 @@ impl TextBox { } } - fn handle_keydown(&mut self, root: &mut NodeMut, data: &KeyboardData) { + fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { let key = data.key(); let modifiers = data.modifiers(); let code = data.code(); @@ -203,14 +201,12 @@ impl TextBox { } } - fn handle_mousemove(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { if self.dragging { let id = root.id(); let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } + // textboxs are only one line tall new.row = 0; @@ -222,12 +218,9 @@ impl TextBox { } } - fn handle_mousedown(&mut self, root: &mut NodeMut, data: &MouseData) { + fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { let offset = data.element_coordinates(); let mut new = Pos::new(offset.x as usize, offset.y as usize); - if self.border { - new.col = new.col.saturating_sub(1); - } // textboxs are only one line tall new.row = 0; @@ -265,10 +258,14 @@ impl TextBox { } } -impl Widget for TextBox { +impl CustomElement for TextBox { const NAME: &'static str = "input"; - fn create(root: &mut dioxus_native_core::real_dom::NodeMut<()>) -> Self { + fn roots(&self) -> Vec { + vec![self.div_wrapper] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { let node_type = root.node_type(); let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; @@ -332,8 +329,6 @@ impl Widget for TextBox { root.add_event_listener("keydown"); root.add_event_listener("focusout"); - root.add_child(div_wrapper_id); - Self { pre_cursor_text: pre_text_id, highlighted_text: highlighted_text_id, @@ -347,7 +342,7 @@ impl Widget for TextBox { fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut<()>, + mut root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { match attributes { @@ -386,11 +381,7 @@ impl Widget for TextBox { } impl RinkWidget for TextBox { - fn handle_event( - &mut self, - event: &crate::Event, - node: &mut dioxus_native_core::real_dom::NodeMut, - ) { + fn handle_event(&mut self, event: &crate::Event, node: NodeMut) { match event.name { "keydown" => { if let EventData::Keyboard(data) = &event.data { From ea5a6775a2bc06b458cb5602205ec6972ac75a87 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 14 Apr 2023 14:58:48 -0500 Subject: [PATCH 438/895] bump sledgehammer-bindgen version --- packages/interpreter/Cargo.toml | 5 ++--- packages/interpreter/src/sledgehammer_bindings.rs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/interpreter/Cargo.toml b/packages/interpreter/Cargo.toml index 7c7d79607..5b460ed73 100644 --- a/packages/interpreter/Cargo.toml +++ b/packages/interpreter/Cargo.toml @@ -10,15 +10,14 @@ homepage = "https://dioxuslabs.com" documentation = "https://docs.rs/dioxus" keywords = ["dom", "ui", "gui", "react", "wasm"] - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] wasm-bindgen = { version = "0.2.79", 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.1.3", optional = true } -sledgehammer_utils = { version = "0.1.0", optional = true } +sledgehammer_bindgen = { version = "0.2.0", optional = true } +sledgehammer_utils = { version = "0.1.1", optional = true } [features] default = [] diff --git a/packages/interpreter/src/sledgehammer_bindings.rs b/packages/interpreter/src/sledgehammer_bindings.rs index 33f6b4420..b1b82823c 100644 --- a/packages/interpreter/src/sledgehammer_bindings.rs +++ b/packages/interpreter/src/sledgehammer_bindings.rs @@ -108,6 +108,7 @@ mod js { const listeners = new ListenerMap(); let nodes = []; let stack = []; + let root; const templates = {}; let node, els, end, ptr_end, k; export function save_template(nodes, tmpl_id) { From c113d96bbe0a952f51652f019f5c313ac5c0257b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Sat, 15 Apr 2023 15:02:04 +0200 Subject: [PATCH 439/895] fix: Update logos and custom assets example (#960) * fix: Update logo and custom assets example * update old logos --- examples/assets/logo.png | Bin 59292 -> 14861 bytes examples/custom_assets.rs | 5 +++-- packages/desktop/src/assets/default_icon.bin | Bin 846400 -> 846400 bytes packages/desktop/src/assets/default_icon.png | Bin 77196 -> 14861 bytes 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/assets/logo.png b/examples/assets/logo.png index 7d08f2af8f057780eddae4b0f8b8fa753b69e7f8..4ad62768f29309905b53a1181894cd0111f8e83c 100644 GIT binary patch literal 14861 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%0D^qA*!{|>uFYu0Rew6FdGz_ypLmc;{8EZG6By#Gf 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 Element { cx.render(rsx! { div { - "This should show an image:" + p { + "This should show an image:" + } img { src: "examples/assets/logo.png" } - img { src: "/Users/jonkelley/Desktop/blitz.png" } } }) } diff --git a/packages/desktop/src/assets/default_icon.bin b/packages/desktop/src/assets/default_icon.bin index 2d4898f0cabc546d8fd1dc1127f8fe8e648f5aaa..bf78dc11541a817c9327525690b7e2730a0193a2 100644 GIT binary patch literal 846400 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 V2#A0Ph=2%)fCz|y2-GKme*uRv2jc($ diff --git a/packages/desktop/src/assets/default_icon.png b/packages/desktop/src/assets/default_icon.png index d0742ea8a067fdcdbd24b45866ec7794dfa4a399..4ad62768f29309905b53a1181894cd0111f8e83c 100644 GIT binary patch literal 14861 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%0D^qA*!{|>uFYu0Rew6FdGz_ypLmc;{8EZG6By#Gf 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

M;Ig0xsnp{B?j30@}Tazxg}1i|Tbn@eJK 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 E0YnYs?f?J) From baeb4251bab9b601be4f994534627f98ecf6df1f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 16 Apr 2023 14:05:27 -0500 Subject: [PATCH 440/895] refactor text inputs --- packages/rink/src/widgets/mod.rs | 1 + packages/rink/src/widgets/number.rs | 465 +++---------------------- packages/rink/src/widgets/password.rs | 422 +--------------------- packages/rink/src/widgets/text_like.rs | 444 +++++++++++++++++++++++ packages/rink/src/widgets/textbox.rs | 424 +--------------------- 5 files changed, 504 insertions(+), 1252 deletions(-) create mode 100644 packages/rink/src/widgets/text_like.rs diff --git a/packages/rink/src/widgets/mod.rs b/packages/rink/src/widgets/mod.rs index 27dea751d..c3ecaad78 100644 --- a/packages/rink/src/widgets/mod.rs +++ b/packages/rink/src/widgets/mod.rs @@ -4,6 +4,7 @@ mod input; mod number; mod password; mod slider; +mod text_like; mod textbox; use std::sync::{Arc, RwLock}; diff --git a/packages/rink/src/widgets/number.rs b/packages/rink/src/widgets/number.rs index c83d514b5..371c8b41d 100644 --- a/packages/rink/src/widgets/number.rs +++ b/packages/rink/src/widgets/number.rs @@ -1,291 +1,28 @@ -use std::{collections::HashMap, io::stdout}; - -use crossterm::{cursor::MoveTo, execute}; -use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; +use dioxus_html::input_data::keyboard_types::Key; use dioxus_native_core::{ custom_element::CustomElement, - node::OwnedAttributeDiscription, - node_ref::AttributeMask, - prelude::{ElementNode, NodeType}, - real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::cursor::{Cursor, Pos}, + real_dom::{NodeImmutable, RealDom}, NodeId, }; -use shipyard::UniqueView; -use taffy::geometry::Point; -use crate::{query::get_layout, Event, EventData, FormData, Query}; +use crate::EventData; -use super::{RinkWidget, WidgetContext}; +use super::{text_like::TextLike, RinkWidget}; #[derive(Debug, Default)] pub(crate) struct Number { - text: String, - div_wrapper: NodeId, - pre_cursor_text: NodeId, - highlighted_text: NodeId, - post_cursor_text: NodeId, - cursor: Cursor, - dragging: bool, - border: bool, - max_len: Option, + text: TextLike, } impl Number { - fn width(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "width".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } + fn increase(&mut self, rdom: &mut RealDom, id: NodeId) { + let num = self.text.text().parse::().unwrap_or(0.0); + self.text.set_text((num + 1.0).to_string(), rdom, id); } - fn height(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "height".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } - } - - fn update_max_width_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "maxlength".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - if let Ok(max_len) = value.parse::() { - self.max_len = Some(max_len); - } - } - } - - fn update_size_attr(&mut self, el: &mut ElementNodeMut) { - let width = Self::width(el); - let height = Self::height(el); - let single_char = width - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some() - || height - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some(); - self.border = !single_char; - let border_style = if self.border { "solid" } else { "none" }; - el.set_attribute( - OwnedAttributeDiscription { - name: "border-style".to_string(), - namespace: Some("style".to_string()), - }, - border_style.to_string(), - ); - } - - fn update_value_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - self.text = value; - } - } - - fn write_value(&self, rdom: &mut RealDom, id: NodeId) { - let start_highlight = self.cursor.first().idx(self.text.as_str()); - let end_highlight = self.cursor.last().idx(self.text.as_str()); - let (text_before_first_cursor, text_after_first_cursor) = - self.text.split_at(start_highlight); - let (text_highlighted, text_after_second_cursor) = - text_after_first_cursor.split_at(end_highlight - start_highlight); - - if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_before_first_cursor.to_string(); - } - - if let Some(mut text) = rdom.get_mut(self.highlighted_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_highlighted.to_string(); - } - - if let Some(mut text) = rdom.get_mut(self.post_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_after_second_cursor.to_string(); - } - - // send the event - { - let world = rdom.raw_world_mut(); - let data = FormData { - value: self.text.clone(), - values: HashMap::new(), - files: None, - }; - let ctx: UniqueView = world.borrow().expect("expected widget context"); - - ctx.send(Event { - id, - name: "input", - data: EventData::Form(data), - bubbles: true, - }); - } - } - - fn increase(&mut self) { - let num = self.text.parse::().unwrap_or(0.0); - self.text = (num + 1.0).to_string(); - } - - fn decrease(&mut self) { - let num = self.text.parse::().unwrap_or(0.0); - self.text = (num - 1.0).to_string(); - } - - fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { - let key = data.key(); - let is_text = match key.clone() { - Key::ArrowLeft | Key::ArrowRight | Key::Backspace => true, - Key::Character(c) if c == "." || c == "-" || c.chars().all(|c| c.is_numeric()) => true, - _ => false, - }; - - if is_text { - let modifiers = data.modifiers(); - let code = data.code(); - - if key == Key::Enter { - return; - } - self.cursor.handle_input( - &code, - &key, - &modifiers, - &mut self.text, - self.max_len.unwrap_or(1000), - ); - - let id = root.id(); - - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - let world = rdom.raw_world_mut(); - - // move cursor to new position - let taffy = { - let query: UniqueView = world.borrow().unwrap(); - query.stretch.clone() - }; - - let taffy = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - match key { - Key::ArrowUp => { - self.increase(); - } - Key::ArrowDown => { - self.decrease(); - } - _ => (), - } - - let id = root.id(); - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - } - } - - fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { - if self.dragging { - let id = root.id(); - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - // textboxs are only one line tall - new.row = 0; - - if new != self.cursor.start { - self.cursor.end = Some(new); - } - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - } - } - - fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - - // textboxs are only one line tall - new.row = 0; - - new.realize_col(self.text.as_str()); - self.cursor = Cursor::from_start(new); - self.dragging = true; - - let id = root.id(); - - // move cursor to new position - 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 = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - - self.write_value(rdom, id) + fn decrease(&mut self, rdom: &mut RealDom, id: NodeId) { + let num = self.text.text().parse::().unwrap_or(0.0); + self.text.set_text((num - 1.0).to_string(), rdom, id); } } @@ -293,162 +30,62 @@ impl CustomElement for Number { const NAME: &'static str = "input"; fn roots(&self) -> Vec { - vec![self.div_wrapper] + self.text.roots() } fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { - let node_type = root.node_type(); - let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; - - let value = el - .attributes - .get(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()); - - drop(node_type); - - let rdom = root.real_dom_mut(); - - let pre_text = rdom.create_node(String::new()); - let pre_text_id = pre_text.id(); - let highlighted_text = rdom.create_node(String::new()); - let highlighted_text_id = highlighted_text.id(); - let mut highlighted_text_span = rdom.create_node(NodeType::Element(ElementNode { - tag: "span".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "background-color".to_string(), - namespace: Some("style".to_string()), - }, - "rgba(255, 255, 255, 50%)".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - highlighted_text_span.add_child(highlighted_text_id); - let highlighted_text_span_id = highlighted_text_span.id(); - let post_text = rdom.create_node(value.clone().unwrap_or_default()); - let post_text_id = post_text.id(); - let mut div_wrapper = rdom.create_node(NodeType::Element(ElementNode { - tag: "div".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "display".to_string(), - namespace: Some("style".to_string()), - }, - "flex".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - let div_wrapper_id = div_wrapper.id(); - div_wrapper.add_child(pre_text_id); - div_wrapper.add_child(highlighted_text_span_id); - div_wrapper.add_child(post_text_id); - - div_wrapper.add_event_listener("mousemove"); - div_wrapper.add_event_listener("mousedown"); - div_wrapper.add_event_listener("mouseup"); - div_wrapper.add_event_listener("mouseleave"); - div_wrapper.add_event_listener("mouseenter"); - root.add_event_listener("keydown"); - root.add_event_listener("focusout"); - - Self { - pre_cursor_text: pre_text_id, - highlighted_text: highlighted_text_id, - post_cursor_text: post_text_id, - div_wrapper: div_wrapper_id, - cursor: Cursor::default(), - text: value.unwrap_or_default(), - ..Default::default() + Number { + text: TextLike::create(root.reborrow()), } } fn attributes_changed( &mut self, - mut root: dioxus_native_core::real_dom::NodeMut, + root: dioxus_native_core::real_dom::NodeMut, attributes: &dioxus_native_core::node_ref::AttributeMask, ) { - match attributes { - AttributeMask::All => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - self.update_value_attr(&el); - self.update_size_attr(&mut el); - self.update_max_width_attr(&el); - } - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - AttributeMask::Some(attrs) => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - if attrs.contains("width") || attrs.contains("height") { - self.update_size_attr(&mut el); - } - if attrs.contains("maxlength") { - self.update_max_width_attr(&el); - } - if attrs.contains("value") { - self.update_value_attr(&el); - } - } - if attrs.contains("value") { - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - } - } + self.text.attributes_changed(root, attributes) } } impl RinkWidget for Number { - fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { - match event.name { - "keydown" => { - if let EventData::Keyboard(data) = &event.data { - self.handle_keydown(node, data); + fn handle_event( + &mut self, + event: &crate::Event, + mut node: dioxus_native_core::real_dom::NodeMut, + ) { + if event.name == "keydown" { + if let EventData::Keyboard(data) = &event.data { + let key = data.key(); + let is_num_like = match key.clone() { + Key::ArrowLeft | Key::ArrowRight | Key::Backspace => true, + Key::Character(c) + if c == "." || c == "-" || c.chars().all(|c| c.is_numeric()) => + { + true + } + _ => false, + }; + + if is_num_like { + self.text.handle_event(event, node) + } else { + let id = node.id(); + let rdom = node.real_dom_mut(); + match key { + Key::ArrowUp => { + self.increase(rdom, id); + } + Key::ArrowDown => { + self.decrease(rdom, id); + } + _ => (), + } } + return; } - - "mousemove" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousemove(node, data); - } - } - - "mousedown" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousedown(node, data); - } - } - - "mouseup" => { - self.dragging = false; - } - - "mouseleave" => { - self.dragging = false; - } - - "mouseenter" => { - self.dragging = false; - } - - "focusout" => { - execute!(stdout(), MoveTo(0, 1000)).unwrap(); - } - - _ => {} } + + self.text.handle_event(event, node) } } diff --git a/packages/rink/src/widgets/password.rs b/packages/rink/src/widgets/password.rs index 7e570a631..9a8228ad1 100644 --- a/packages/rink/src/widgets/password.rs +++ b/packages/rink/src/widgets/password.rs @@ -1,422 +1,12 @@ -use std::{collections::HashMap, io::stdout}; +use super::text_like::{TextLike, TextLikeController}; -use crossterm::{cursor::MoveTo, execute}; -use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; -use dioxus_native_core::{ - custom_element::CustomElement, - node::OwnedAttributeDiscription, - node_ref::AttributeMask, - prelude::{ElementNode, NodeType}, - real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::cursor::{Cursor, Pos}, - NodeId, -}; -use shipyard::UniqueView; -use taffy::geometry::Point; - -use crate::{query::get_layout, Event, EventData, FormData, Query}; - -use super::{RinkWidget, WidgetContext}; +pub(crate) type Password = TextLike; #[derive(Debug, Default)] -pub(crate) struct Password { - text: String, - div_wrapper: NodeId, - pre_cursor_text: NodeId, - highlighted_text: NodeId, - post_cursor_text: NodeId, - cursor: Cursor, - dragging: bool, - border: bool, - max_len: Option, -} +pub(crate) struct PasswordController; -impl Password { - fn width(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "width".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } - } - - fn height(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "height".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } - } - - fn update_max_width_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "maxlength".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - if let Ok(max_len) = value.parse::() { - self.max_len = Some(max_len); - } - } - } - - fn update_size_attr(&mut self, el: &mut ElementNodeMut) { - let width = Self::width(el); - let height = Self::height(el); - let single_char = width - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some() - || height - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some(); - self.border = !single_char; - let border_style = if self.border { "solid" } else { "none" }; - el.set_attribute( - OwnedAttributeDiscription { - name: "border-style".to_string(), - namespace: Some("style".to_string()), - }, - border_style.to_string(), - ); - } - - fn update_value_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - self.text = value; - } - } - - fn write_value(&self, rdom: &mut RealDom, id: NodeId) { - let start_highlight = self.cursor.first().idx(self.text.as_str()); - let end_highlight = self.cursor.last().idx(self.text.as_str()); - let (text_before_first_cursor, text_after_first_cursor) = - self.text.split_at(start_highlight); - let (text_highlighted, text_after_second_cursor) = - text_after_first_cursor.split_at(end_highlight - start_highlight); - - if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = ".".repeat(text_before_first_cursor.len()); - } - - if let Some(mut text) = rdom.get_mut(self.highlighted_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = ".".repeat(text_highlighted.len()); - } - - if let Some(mut text) = rdom.get_mut(self.post_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = ".".repeat(text_after_second_cursor.len()); - } - - // send the event - { - let world = rdom.raw_world_mut(); - let data = FormData { - value: self.text.clone(), - values: HashMap::new(), - files: None, - }; - let ctx: UniqueView = world.borrow().expect("expected widget context"); - - ctx.send(Event { - id, - name: "input", - data: EventData::Form(data), - bubbles: true, - }); - } - } - - fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { - let key = data.key(); - let modifiers = data.modifiers(); - let code = data.code(); - - if key == Key::Enter { - return; - } - self.cursor.handle_input( - &code, - &key, - &modifiers, - &mut self.text, - self.max_len.unwrap_or(1000), - ); - - let id = root.id(); - - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - let world = rdom.raw_world_mut(); - - // move cursor to new position - let taffy = { - let query: UniqueView = world.borrow().unwrap(); - query.stretch.clone() - }; - - let taffy = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } - - fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { - if self.dragging { - let id = root.id(); - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - // textboxs are only one line tall - new.row = 0; - - if new != self.cursor.start { - self.cursor.end = Some(new); - } - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - } - } - - fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - - // textboxs are only one line tall - new.row = 0; - - new.realize_col(self.text.as_str()); - self.cursor = Cursor::from_start(new); - self.dragging = true; - - let id = root.id(); - - // move cursor to new position - 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 = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - - self.write_value(rdom, id) - } -} - -impl CustomElement for Password { - const NAME: &'static str = "input"; - - fn roots(&self) -> Vec { - vec![self.div_wrapper] - } - - fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { - let node_type = root.node_type(); - let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; - - let value = el - .attributes - .get(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()); - - drop(node_type); - - let rdom = root.real_dom_mut(); - - let pre_text = rdom.create_node(String::new()); - let pre_text_id = pre_text.id(); - let highlighted_text = rdom.create_node(String::new()); - let highlighted_text_id = highlighted_text.id(); - let mut highlighted_text_span = rdom.create_node(NodeType::Element(ElementNode { - tag: "span".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "background-color".to_string(), - namespace: Some("style".to_string()), - }, - "rgba(255, 255, 255, 50%)".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - highlighted_text_span.add_child(highlighted_text_id); - let highlighted_text_span_id = highlighted_text_span.id(); - let post_text = rdom.create_node(value.clone().unwrap_or_default()); - let post_text_id = post_text.id(); - let mut div_wrapper = rdom.create_node(NodeType::Element(ElementNode { - tag: "div".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "display".to_string(), - namespace: Some("style".to_string()), - }, - "flex".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - let div_wrapper_id = div_wrapper.id(); - div_wrapper.add_child(pre_text_id); - div_wrapper.add_child(highlighted_text_span_id); - div_wrapper.add_child(post_text_id); - - div_wrapper.add_event_listener("mousemove"); - div_wrapper.add_event_listener("mousedown"); - div_wrapper.add_event_listener("mouseup"); - div_wrapper.add_event_listener("mouseleave"); - div_wrapper.add_event_listener("mouseenter"); - root.add_event_listener("keydown"); - root.add_event_listener("focusout"); - - Self { - pre_cursor_text: pre_text_id, - highlighted_text: highlighted_text_id, - post_cursor_text: post_text_id, - div_wrapper: div_wrapper_id, - cursor: Cursor::default(), - text: value.unwrap_or_default(), - ..Default::default() - } - } - - fn attributes_changed( - &mut self, - mut root: dioxus_native_core::real_dom::NodeMut, - attributes: &dioxus_native_core::node_ref::AttributeMask, - ) { - match attributes { - AttributeMask::All => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - self.update_value_attr(&el); - self.update_size_attr(&mut el); - self.update_max_width_attr(&el); - } - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - AttributeMask::Some(attrs) => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - if attrs.contains("width") || attrs.contains("height") { - self.update_size_attr(&mut el); - } - if attrs.contains("maxlength") { - self.update_max_width_attr(&el); - } - if attrs.contains("value") { - self.update_value_attr(&el); - } - } - if attrs.contains("value") { - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - } - } - } -} - -impl RinkWidget for Password { - fn handle_event(&mut self, event: &crate::Event, node: dioxus_native_core::real_dom::NodeMut) { - match event.name { - "keydown" => { - if let EventData::Keyboard(data) = &event.data { - self.handle_keydown(node, data); - } - } - - "mousemove" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousemove(node, data); - } - } - - "mousedown" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousedown(node, data); - } - } - - "mouseup" => { - self.dragging = false; - } - - "mouseleave" => { - self.dragging = false; - } - - "mouseenter" => { - self.dragging = false; - } - - "focusout" => { - execute!(stdout(), MoveTo(0, 1000)).unwrap(); - } - - _ => {} - } +impl TextLikeController for PasswordController { + fn display_text(&self, text: &str) -> String { + text.chars().map(|_| '.').collect() } } diff --git a/packages/rink/src/widgets/text_like.rs b/packages/rink/src/widgets/text_like.rs new file mode 100644 index 000000000..b5874c776 --- /dev/null +++ b/packages/rink/src/widgets/text_like.rs @@ -0,0 +1,444 @@ +use std::{collections::HashMap, io::stdout}; + +use crossterm::{cursor::MoveTo, execute}; +use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; +use dioxus_native_core::{ + custom_element::CustomElement, + node::OwnedAttributeDiscription, + node_ref::AttributeMask, + prelude::{ElementNode, NodeType}, + real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, + utils::cursor::{Cursor, Pos}, + NodeId, +}; +use shipyard::UniqueView; +use taffy::geometry::Point; + +use crate::{query::get_layout, Event, EventData, FormData, Query}; + +use super::{RinkWidget, WidgetContext}; + +pub(crate) trait TextLikeController { + fn display_text(&self, text: &str) -> String { + text.to_string() + } +} + +#[derive(Debug, Default)] +pub(crate) struct EmptyController; + +impl TextLikeController for EmptyController {} + +#[derive(Debug, Default)] +pub(crate) struct TextLike { + text: String, + div_wrapper: NodeId, + pre_cursor_text: NodeId, + highlighted_text: NodeId, + post_cursor_text: NodeId, + cursor: Cursor, + dragging: bool, + border: bool, + max_len: Option, + controller: C, +} + +impl TextLike { + fn width(el: &ElementNodeMut) -> String { + if let Some(value) = el + .get_attribute(&OwnedAttributeDiscription { + name: "width".to_string(), + namespace: Some("style".to_string()), + }) + .and_then(|value| value.as_text()) + .map(|value| value.to_string()) + { + value + } else { + "1px".to_string() + } + } + + fn height(el: &ElementNodeMut) -> String { + if let Some(value) = el + .get_attribute(&OwnedAttributeDiscription { + name: "height".to_string(), + namespace: Some("style".to_string()), + }) + .and_then(|value| value.as_text()) + .map(|value| value.to_string()) + { + value + } else { + "1px".to_string() + } + } + + fn update_max_width_attr(&mut self, el: &ElementNodeMut) { + if let Some(value) = el + .get_attribute(&OwnedAttributeDiscription { + name: "maxlength".to_string(), + namespace: None, + }) + .and_then(|value| value.as_text()) + .map(|value| value.to_string()) + { + if let Ok(max_len) = value.parse::() { + self.max_len = Some(max_len); + } + } + } + + fn update_size_attr(&mut self, el: &mut ElementNodeMut) { + let width = Self::width(el); + let height = Self::height(el); + let single_char = width + .strip_prefix("px") + .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) + .is_some() + || height + .strip_prefix("px") + .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) + .is_some(); + self.border = !single_char; + let border_style = if self.border { "solid" } else { "none" }; + el.set_attribute( + OwnedAttributeDiscription { + name: "border-style".to_string(), + namespace: Some("style".to_string()), + }, + border_style.to_string(), + ); + } + + fn update_value_attr(&mut self, el: &ElementNodeMut) { + if let Some(value) = el + .get_attribute(&OwnedAttributeDiscription { + name: "value".to_string(), + namespace: None, + }) + .and_then(|value| value.as_text()) + .map(|value| value.to_string()) + { + self.text = value; + } + } + + pub(crate) fn set_text(&mut self, text: String, rdom: &mut RealDom, id: NodeId) { + self.text = text; + self.write_value(rdom, id); + } + + pub(crate) fn text(&self) -> &str { + self.text.as_str() + } + + fn write_value(&self, rdom: &mut RealDom, id: NodeId) { + let start_highlight = self.cursor.first().idx(self.text.as_str()); + let end_highlight = self.cursor.last().idx(self.text.as_str()); + let (text_before_first_cursor, text_after_first_cursor) = + self.text.split_at(start_highlight); + let (text_highlighted, text_after_second_cursor) = + text_after_first_cursor.split_at(end_highlight - start_highlight); + + if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) { + let node_type = text.node_type_mut(); + let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; + *text.text_mut() = self.controller.display_text(text_before_first_cursor); + } + + if let Some(mut text) = rdom.get_mut(self.highlighted_text) { + let node_type = text.node_type_mut(); + let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; + *text.text_mut() = self.controller.display_text(text_highlighted); + } + + if let Some(mut text) = rdom.get_mut(self.post_cursor_text) { + let node_type = text.node_type_mut(); + let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; + *text.text_mut() = self.controller.display_text(text_after_second_cursor); + } + + // send the event + { + let world = rdom.raw_world_mut(); + let data: FormData = FormData { + value: self.text.clone(), + values: HashMap::new(), + files: None, + }; + let ctx: UniqueView = world.borrow().expect("expected widget context"); + + ctx.send(Event { + id, + name: "input", + data: EventData::Form(data), + bubbles: true, + }); + } + } + + fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { + let key = data.key(); + let modifiers = data.modifiers(); + let code = data.code(); + + if key == Key::Enter { + return; + } + self.cursor.handle_input( + &code, + &key, + &modifiers, + &mut self.text, + self.max_len.unwrap_or(1000), + ); + + let id = root.id(); + + let rdom = root.real_dom_mut(); + self.write_value(rdom, id); + let world = rdom.raw_world_mut(); + + // move cursor to new position + let taffy = { + let query: UniqueView = world.borrow().unwrap(); + query.stretch.clone() + }; + + let taffy = taffy.lock().unwrap(); + + let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); + let Point { x, y } = layout.location; + + let Pos { col, row } = self.cursor.start; + let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); + if let Ok(pos) = crossterm::cursor::position() { + if pos != (x, y) { + execute!(stdout(), MoveTo(x, y)).unwrap(); + } + } else { + execute!(stdout(), MoveTo(x, y)).unwrap(); + } + } + + fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { + if self.dragging { + let id = root.id(); + let offset = data.element_coordinates(); + let mut new = Pos::new(offset.x as usize, offset.y as usize); + + // textboxs are only one line tall + new.row = 0; + + if new != self.cursor.start { + self.cursor.end = Some(new); + } + let rdom = root.real_dom_mut(); + self.write_value(rdom, id); + } + } + + fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { + let offset = data.element_coordinates(); + let mut new = Pos::new(offset.x as usize, offset.y as usize); + + // textboxs are only one line tall + new.row = 0; + + new.realize_col(self.text.as_str()); + self.cursor = Cursor::from_start(new); + self.dragging = true; + + let id = root.id(); + + // move cursor to new position + 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 = taffy.lock().unwrap(); + + let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); + let Point { x, y } = layout.location; + + let Pos { col, row } = self.cursor.start; + let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); + if let Ok(pos) = crossterm::cursor::position() { + if pos != (x, y) { + execute!(stdout(), MoveTo(x, y)).unwrap(); + } + } else { + execute!(stdout(), MoveTo(x, y)).unwrap(); + } + + self.write_value(rdom, id) + } +} + +impl CustomElement for TextLike { + const NAME: &'static str = "input"; + + fn roots(&self) -> Vec { + vec![self.div_wrapper] + } + + fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { + let node_type = root.node_type(); + let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; + + let value = el + .attributes + .get(&OwnedAttributeDiscription { + name: "value".to_string(), + namespace: None, + }) + .and_then(|value| value.as_text()) + .map(|value| value.to_string()); + + drop(node_type); + + let rdom = root.real_dom_mut(); + + let pre_text = rdom.create_node(String::new()); + let pre_text_id = pre_text.id(); + let highlighted_text = rdom.create_node(String::new()); + let highlighted_text_id = highlighted_text.id(); + let mut highlighted_text_span = rdom.create_node(NodeType::Element(ElementNode { + tag: "span".to_string(), + attributes: [( + OwnedAttributeDiscription { + name: "background-color".to_string(), + namespace: Some("style".to_string()), + }, + "rgba(255, 255, 255, 50%)".to_string().into(), + )] + .into_iter() + .collect(), + ..Default::default() + })); + highlighted_text_span.add_child(highlighted_text_id); + let highlighted_text_span_id = highlighted_text_span.id(); + let post_text = rdom.create_node(value.clone().unwrap_or_default()); + let post_text_id = post_text.id(); + let mut div_wrapper = rdom.create_node(NodeType::Element(ElementNode { + tag: "div".to_string(), + attributes: [( + OwnedAttributeDiscription { + name: "display".to_string(), + namespace: Some("style".to_string()), + }, + "flex".to_string().into(), + )] + .into_iter() + .collect(), + ..Default::default() + })); + let div_wrapper_id = div_wrapper.id(); + div_wrapper.add_child(pre_text_id); + div_wrapper.add_child(highlighted_text_span_id); + div_wrapper.add_child(post_text_id); + + div_wrapper.add_event_listener("mousemove"); + div_wrapper.add_event_listener("mousedown"); + div_wrapper.add_event_listener("mouseup"); + div_wrapper.add_event_listener("mouseleave"); + div_wrapper.add_event_listener("mouseenter"); + root.add_event_listener("keydown"); + root.add_event_listener("focusout"); + + Self { + pre_cursor_text: pre_text_id, + highlighted_text: highlighted_text_id, + post_cursor_text: post_text_id, + div_wrapper: div_wrapper_id, + cursor: Cursor::default(), + text: value.unwrap_or_default(), + ..Default::default() + } + } + + fn attributes_changed( + &mut self, + mut root: dioxus_native_core::real_dom::NodeMut, + attributes: &dioxus_native_core::node_ref::AttributeMask, + ) { + match attributes { + AttributeMask::All => { + { + let node_type = root.node_type_mut(); + let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; + self.update_value_attr(&el); + self.update_size_attr(&mut el); + self.update_max_width_attr(&el); + } + let id = root.id(); + self.write_value(root.real_dom_mut(), id); + } + AttributeMask::Some(attrs) => { + { + let node_type = root.node_type_mut(); + let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; + if attrs.contains("width") || attrs.contains("height") { + self.update_size_attr(&mut el); + } + if attrs.contains("maxlength") { + self.update_max_width_attr(&el); + } + if attrs.contains("value") { + self.update_value_attr(&el); + } + } + if attrs.contains("value") { + let id = root.id(); + self.write_value(root.real_dom_mut(), id); + } + } + } + } +} + +impl RinkWidget for TextLike { + fn handle_event(&mut self, event: &crate::Event, node: NodeMut) { + match event.name { + "keydown" => { + if let EventData::Keyboard(data) = &event.data { + self.handle_keydown(node, data); + } + } + + "mousemove" => { + if let EventData::Mouse(data) = &event.data { + self.handle_mousemove(node, data); + } + } + + "mousedown" => { + if let EventData::Mouse(data) = &event.data { + self.handle_mousedown(node, data); + } + } + + "mouseup" => { + self.dragging = false; + } + + "mouseleave" => { + self.dragging = false; + } + + "mouseenter" => { + self.dragging = false; + } + + "focusout" => { + execute!(stdout(), MoveTo(0, 1000)).unwrap(); + } + + _ => {} + } + } +} diff --git a/packages/rink/src/widgets/textbox.rs b/packages/rink/src/widgets/textbox.rs index 8eaadb7a7..df9bd7758 100644 --- a/packages/rink/src/widgets/textbox.rs +++ b/packages/rink/src/widgets/textbox.rs @@ -1,423 +1,3 @@ -use std::{collections::HashMap, io::stdout}; +use super::text_like::TextLike; -use crossterm::{cursor::MoveTo, execute}; -use dioxus_html::{input_data::keyboard_types::Key, KeyboardData, MouseData}; -use dioxus_native_core::{ - custom_element::CustomElement, - node::OwnedAttributeDiscription, - node_ref::AttributeMask, - prelude::{ElementNode, NodeType}, - real_dom::{ElementNodeMut, NodeImmutable, NodeMut, NodeTypeMut, RealDom}, - utils::cursor::{Cursor, Pos}, - NodeId, -}; -use shipyard::UniqueView; -use taffy::geometry::Point; - -use crate::{query::get_layout, Event, EventData, FormData, Query}; - -use super::{RinkWidget, WidgetContext}; - -#[derive(Debug, Default)] -pub(crate) struct TextBox { - text: String, - div_wrapper: NodeId, - pre_cursor_text: NodeId, - highlighted_text: NodeId, - post_cursor_text: NodeId, - cursor: Cursor, - dragging: bool, - border: bool, - max_len: Option, -} - -impl TextBox { - fn width(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "width".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } - } - - fn height(el: &ElementNodeMut) -> String { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "height".to_string(), - namespace: Some("style".to_string()), - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - value - } else { - "1px".to_string() - } - } - - fn update_max_width_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "maxlength".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - if let Ok(max_len) = value.parse::() { - self.max_len = Some(max_len); - } - } - } - - fn update_size_attr(&mut self, el: &mut ElementNodeMut) { - let width = Self::width(el); - let height = Self::height(el); - let single_char = width - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some() - || height - .strip_prefix("px") - .and_then(|n| n.parse::().ok().filter(|num| *num > 3)) - .is_some(); - self.border = !single_char; - let border_style = if self.border { "solid" } else { "none" }; - el.set_attribute( - OwnedAttributeDiscription { - name: "border-style".to_string(), - namespace: Some("style".to_string()), - }, - border_style.to_string(), - ); - } - - fn update_value_attr(&mut self, el: &ElementNodeMut) { - if let Some(value) = el - .get_attribute(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()) - { - self.text = value; - } - } - - fn write_value(&self, rdom: &mut RealDom, id: NodeId) { - let start_highlight = self.cursor.first().idx(self.text.as_str()); - let end_highlight = self.cursor.last().idx(self.text.as_str()); - let (text_before_first_cursor, text_after_first_cursor) = - self.text.split_at(start_highlight); - let (text_highlighted, text_after_second_cursor) = - text_after_first_cursor.split_at(end_highlight - start_highlight); - - if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_before_first_cursor.to_string(); - } - - if let Some(mut text) = rdom.get_mut(self.highlighted_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_highlighted.to_string(); - } - - if let Some(mut text) = rdom.get_mut(self.post_cursor_text) { - let node_type = text.node_type_mut(); - let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") }; - *text.text_mut() = text_after_second_cursor.to_string(); - } - - // send the event - { - let world = rdom.raw_world_mut(); - let data = FormData { - value: self.text.clone(), - values: HashMap::new(), - files: None, - }; - let ctx: UniqueView = world.borrow().expect("expected widget context"); - - ctx.send(Event { - id, - name: "input", - data: EventData::Form(data), - bubbles: true, - }); - } - } - - fn handle_keydown(&mut self, mut root: NodeMut, data: &KeyboardData) { - let key = data.key(); - let modifiers = data.modifiers(); - let code = data.code(); - - if key == Key::Enter { - return; - } - self.cursor.handle_input( - &code, - &key, - &modifiers, - &mut self.text, - self.max_len.unwrap_or(1000), - ); - - let id = root.id(); - - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - let world = rdom.raw_world_mut(); - - // move cursor to new position - let taffy = { - let query: UniqueView = world.borrow().unwrap(); - query.stretch.clone() - }; - - let taffy = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } - - fn handle_mousemove(&mut self, mut root: NodeMut, data: &MouseData) { - if self.dragging { - let id = root.id(); - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - - // textboxs are only one line tall - new.row = 0; - - if new != self.cursor.start { - self.cursor.end = Some(new); - } - let rdom = root.real_dom_mut(); - self.write_value(rdom, id); - } - } - - fn handle_mousedown(&mut self, mut root: NodeMut, data: &MouseData) { - let offset = data.element_coordinates(); - let mut new = Pos::new(offset.x as usize, offset.y as usize); - - // textboxs are only one line tall - new.row = 0; - - new.realize_col(self.text.as_str()); - self.cursor = Cursor::from_start(new); - self.dragging = true; - - let id = root.id(); - - // move cursor to new position - 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 = taffy.lock().unwrap(); - - let layout = get_layout(rdom.get(self.div_wrapper).unwrap(), &taffy).unwrap(); - let Point { x, y } = layout.location; - - let Pos { col, row } = self.cursor.start; - let (x, y) = (col as u16 + x as u16, row as u16 + y as u16); - if let Ok(pos) = crossterm::cursor::position() { - if pos != (x, y) { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - } else { - execute!(stdout(), MoveTo(x, y)).unwrap(); - } - - self.write_value(rdom, id) - } -} - -impl CustomElement for TextBox { - const NAME: &'static str = "input"; - - fn roots(&self) -> Vec { - vec![self.div_wrapper] - } - - fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self { - let node_type = root.node_type(); - let NodeType::Element(el) = &*node_type else { panic!("input must be an element") }; - - let value = el - .attributes - .get(&OwnedAttributeDiscription { - name: "value".to_string(), - namespace: None, - }) - .and_then(|value| value.as_text()) - .map(|value| value.to_string()); - - drop(node_type); - - let rdom = root.real_dom_mut(); - - let pre_text = rdom.create_node(String::new()); - let pre_text_id = pre_text.id(); - let highlighted_text = rdom.create_node(String::new()); - let highlighted_text_id = highlighted_text.id(); - let mut highlighted_text_span = rdom.create_node(NodeType::Element(ElementNode { - tag: "span".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "background-color".to_string(), - namespace: Some("style".to_string()), - }, - "rgba(255, 255, 255, 50%)".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - highlighted_text_span.add_child(highlighted_text_id); - let highlighted_text_span_id = highlighted_text_span.id(); - let post_text = rdom.create_node(value.clone().unwrap_or_default()); - let post_text_id = post_text.id(); - let mut div_wrapper = rdom.create_node(NodeType::Element(ElementNode { - tag: "div".to_string(), - attributes: [( - OwnedAttributeDiscription { - name: "display".to_string(), - namespace: Some("style".to_string()), - }, - "flex".to_string().into(), - )] - .into_iter() - .collect(), - ..Default::default() - })); - let div_wrapper_id = div_wrapper.id(); - div_wrapper.add_child(pre_text_id); - div_wrapper.add_child(highlighted_text_span_id); - div_wrapper.add_child(post_text_id); - - div_wrapper.add_event_listener("mousemove"); - div_wrapper.add_event_listener("mousedown"); - div_wrapper.add_event_listener("mouseup"); - div_wrapper.add_event_listener("mouseleave"); - div_wrapper.add_event_listener("mouseenter"); - root.add_event_listener("keydown"); - root.add_event_listener("focusout"); - - Self { - pre_cursor_text: pre_text_id, - highlighted_text: highlighted_text_id, - post_cursor_text: post_text_id, - div_wrapper: div_wrapper_id, - cursor: Cursor::default(), - text: value.unwrap_or_default(), - ..Default::default() - } - } - - fn attributes_changed( - &mut self, - mut root: dioxus_native_core::real_dom::NodeMut, - attributes: &dioxus_native_core::node_ref::AttributeMask, - ) { - match attributes { - AttributeMask::All => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - self.update_value_attr(&el); - self.update_size_attr(&mut el); - self.update_max_width_attr(&el); - } - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - AttributeMask::Some(attrs) => { - { - let node_type = root.node_type_mut(); - let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") }; - if attrs.contains("width") || attrs.contains("height") { - self.update_size_attr(&mut el); - } - if attrs.contains("maxlength") { - self.update_max_width_attr(&el); - } - if attrs.contains("value") { - self.update_value_attr(&el); - } - } - if attrs.contains("value") { - let id = root.id(); - self.write_value(root.real_dom_mut(), id); - } - } - } - } -} - -impl RinkWidget for TextBox { - fn handle_event(&mut self, event: &crate::Event, node: NodeMut) { - match event.name { - "keydown" => { - if let EventData::Keyboard(data) = &event.data { - self.handle_keydown(node, data); - } - } - - "mousemove" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousemove(node, data); - } - } - - "mousedown" => { - if let EventData::Mouse(data) = &event.data { - self.handle_mousedown(node, data); - } - } - - "mouseup" => { - self.dragging = false; - } - - "mouseleave" => { - self.dragging = false; - } - - "mouseenter" => { - self.dragging = false; - } - - "focusout" => { - execute!(stdout(), MoveTo(0, 1000)).unwrap(); - } - - _ => {} - } - } -} +pub(crate) type TextBox = TextLike; From 12004578805449b21118c62e15066e9c6fe907de Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 17 Apr 2023 07:18:26 -0500 Subject: [PATCH 441/895] bump sledgehammer version --- 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 5b460ed73..76f9e19ca 100644 --- a/packages/interpreter/Cargo.toml +++ b/packages/interpreter/Cargo.toml @@ -16,7 +16,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] wasm-bindgen = { version = "0.2.79", 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.0", optional = true } +sledgehammer_bindgen = { version = "0.2.1", optional = true } sledgehammer_utils = { version = "0.1.1", optional = true } [features] From 9877b0f0b12270b1041b7be06bf6604aa9be7738 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 17 Apr 2023 12:41:54 -0500 Subject: [PATCH 442/895] finish shadow dom docs --- packages/native-core/examples/custom_attr.rs | 2 +- packages/native-core/examples/font_size.rs | 2 +- packages/native-core/examples/simple.rs | 2 +- .../native-core/examples/simple_dioxus.rs | 2 +- packages/native-core/src/custom_element.rs | 81 ++++++++++--------- packages/native-core/src/real_dom.rs | 62 ++++++++++++-- packages/native-core/src/tree.rs | 31 ++++--- .../tests/called_minimally_on_build.rs | 2 +- packages/native-core/tests/custom_element.rs | 2 +- packages/rink/src/focus.rs | 4 +- packages/rink/src/hooks.rs | 2 +- 11 files changed, 123 insertions(+), 69 deletions(-) diff --git a/packages/native-core/examples/custom_attr.rs b/packages/native-core/examples/custom_attr.rs index ee78a69f4..e7bbb36ea 100644 --- a/packages/native-core/examples/custom_attr.rs +++ b/packages/native-core/examples/custom_attr.rs @@ -215,7 +215,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(true, |node| { + rdom.traverse_depth_first_advanced(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/font_size.rs b/packages/native-core/examples/font_size.rs index 4ff6b876d..40261baa2 100644 --- a/packages/native-core/examples/font_size.rs +++ b/packages/native-core/examples/font_size.rs @@ -160,7 +160,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(true, |node| { + rdom.traverse_depth_first_advanced(true, |node| { let indent = " ".repeat(node.height() as usize); let font_size = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/simple.rs b/packages/native-core/examples/simple.rs index b44f05e63..276d06d08 100644 --- a/packages/native-core/examples/simple.rs +++ b/packages/native-core/examples/simple.rs @@ -206,7 +206,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(true, |node| { + rdom.traverse_depth_first_advanced(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/examples/simple_dioxus.rs b/packages/native-core/examples/simple_dioxus.rs index c5aebd5d3..af0e4ca00 100644 --- a/packages/native-core/examples/simple_dioxus.rs +++ b/packages/native-core/examples/simple_dioxus.rs @@ -234,7 +234,7 @@ fn main() -> Result<(), Box> { let _to_rerender = rdom.update_state(ctx); // render... - rdom.traverse_depth_first(true, |node| { + rdom.traverse_depth_first_advanced(true, |node| { let indent = " ".repeat(node.height() as usize); let color = *node.get::().unwrap(); let size = *node.get::().unwrap(); diff --git a/packages/native-core/src/custom_element.rs b/packages/native-core/src/custom_element.rs index 675e928f1..3675089f6 100644 --- a/packages/native-core/src/custom_element.rs +++ b/packages/native-core/src/custom_element.rs @@ -1,5 +1,10 @@ -//! A custom element is a controlled element that renders to a shadow DOM. -//! Each custom element is registered with a element name +//! A custom element is a controlled element that renders to a shadow DOM. This allows you to create elements that act like widgets without relying on a specific framework. +//! +//! Each custom element is registered with a element name and namespace with [`RealDom::register_custom_element`] or [`RealDom::register_custom_element_with_factory`]. Once registered, they will be created automatically when the element is added to the DOM. + +// Used in doc links +#[allow(unused)] +use crate::real_dom::RealDom; use std::sync::{Arc, RwLock}; @@ -48,22 +53,22 @@ impl CustomElementRegistry { }; if let Some((tag, ns)) = element_tag { if let Some(builder) = self.builders.get(&(tag.as_str(), ns.as_deref())) { - let boxed_widget = { (builder.create)(node.reborrow()) }; + let boxed_custom_element = { (builder.create)(node.reborrow()) }; - let shadow_roots = boxed_widget.roots(); + let shadow_roots = boxed_custom_element.roots(); let light_id = node.id(); node.real_dom_mut().tree_mut().create_subtree( light_id, shadow_roots, - boxed_widget.slot(), + boxed_custom_element.slot(), ); - let boxed_widget = CustomElementManager { - inner: Arc::new(RwLock::new(boxed_widget)), + let boxed_custom_element = CustomElementManager { + inner: Arc::new(RwLock::new(boxed_custom_element)), }; - node.insert(boxed_widget); + node.insert(boxed_custom_element); } } } @@ -73,40 +78,49 @@ struct CustomElementBuilder { create: fn(NodeMut) -> Box>, } -/// A controlled element that renders to a shadow DOM +/// A controlled element that renders to a shadow DOM. +/// +/// Register with [`RealDom::register_custom_element`] +/// +/// This is a simplified custom element trait for elements that can create themselves. For more granular control, implement [`CustomElementFactory`] and [`CustomElementUpdater`] instead. pub trait CustomElement: Send + Sync + 'static { - /// The tag the widget is registered under. + /// The tag of the element const NAME: &'static str; - /// The namespace the widget is registered under. + /// The namespace of the element const NAMESPACE: Option<&'static str> = None; - /// Create a new widget *without mounting* it. - fn create(node: NodeMut) -> Self; + /// Create a new element *without mounting* it. + /// The node passed in is the light DOM node. The element should not modify the light DOM node, but it can get the [`NodeMut::real_dom_mut`] from the node to create new nodes. + fn create(light_root: NodeMut) -> Self; - /// The root node of the widget. This must be static once the element is created. + /// The root node of the custom element. These roots must be not change once the element is created. fn roots(&self) -> Vec; - /// The slot to render children of the element into. This must be static once the element is created. + /// The slot to render children of the element into. The slot must be not change once the element is created. fn slot(&self) -> Option { None } - /// Called when the attributes of the widget are changed. + /// Update the custom element's shadow tree with the new attributes. + /// Called when the attributes of the custom element are changed. fn attributes_changed(&mut self, light_node: NodeMut, attributes: &AttributeMask); } -/// A factory for creating widgets +/// A factory for creating custom elements +/// +/// Register with [`RealDom::register_custom_element_with_factory`] pub trait CustomElementFactory, V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static { - /// The tag the widget is registered under. + /// The tag of the element const NAME: &'static str; - /// The namespace the widget is registered under. + /// The namespace of the element const NAMESPACE: Option<&'static str> = None; - /// Create a new widget. + /// Create a new element *without mounting* it. + /// The node passed in is the light DOM node. The element should not modify the light DOM node, but it can get the [`NodeMut::real_dom_mut`] from the node to create new nodes. fn create(dom: NodeMut) -> W; } @@ -120,16 +134,19 @@ impl, V: FromAnyValue + Send + Sync> CustomElementFactory: Send + Sync + 'static { - /// Called when the attributes of the widget are changed. + /// Update the custom element's shadow tree with the new attributes. + /// Called when the attributes of the custom element are changed. fn attributes_changed(&mut self, light_root: NodeMut, attributes: &AttributeMask); - /// The root node of the widget. + /// The root node of the custom element. These roots must be not change once the element is created. fn roots(&self) -> Vec; - /// The slot to render children of the element into. - fn slot(&self) -> Option; + /// The slot to render children of the element into. The slot must be not change once the element is created. + fn slot(&self) -> Option { + None + } } impl, V: FromAnyValue + Send + Sync> CustomElementUpdater for W { @@ -146,23 +163,13 @@ impl, V: FromAnyValue + Send + Sync> CustomElementUpdater } } -/// A concrete structure for managing a any widget. +/// A dynamic trait object wrapper for [`CustomElementUpdater`] #[derive(Component, Clone)] -pub struct CustomElementManager { +pub(crate) struct CustomElementManager { inner: Arc>>>, } impl CustomElementManager { - /// The root node of the widget's shadow DOM. - pub fn roots(&self) -> Vec { - self.inner.read().unwrap().roots() - } - - /// The slot to render children of the element into. - pub fn slot(&self) -> Option { - self.inner.read().unwrap().slot() - } - /// Update the custom element based on attributes changed. pub fn on_attributes_changed(&self, light_root: NodeMut, attributes: &AttributeMask) { self.inner diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 61e9644a3..a0eff4b2c 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -384,20 +384,35 @@ impl RealDom { } /// Traverses the dom in a depth first manner, calling the provided function on each node. - pub fn traverse_depth_first(&self, enter_shadow_doms: bool, mut f: impl FnMut(NodeRef)) { + /// If `enter_shadow_dom` is true, then the traversal will enter shadow doms in the tree. + pub fn traverse_depth_first_advanced( + &self, + enter_shadow_dom: bool, + mut f: impl FnMut(NodeRef), + ) { let mut stack = vec![self.root_id()]; let tree = self.tree_ref(); while let Some(id) = stack.pop() { if let Some(node) = self.get(id) { f(node); - let children = tree.children_ids_advanced(id, enter_shadow_doms); + let children = tree.children_ids_advanced(id, enter_shadow_dom); stack.extend(children.iter().copied().rev()); } } } + /// Traverses the dom in a depth first manner, calling the provided function on each node. + pub fn traverse_depth_first(&self, f: impl FnMut(NodeRef)) { + self.traverse_depth_first_advanced(true, f) + } + /// Traverses the dom in a breadth first manner, calling the provided function on each node. - pub fn traverse_breadth_first(&self, enter_shadow_doms: bool, mut f: impl FnMut(NodeRef)) { + /// If `enter_shadow_dom` is true, then the traversal will enter shadow doms in the tree. + pub fn traverse_breadth_first_advanced( + &self, + enter_shadow_doms: bool, + mut f: impl FnMut(NodeRef), + ) { let mut queue = VecDeque::new(); queue.push_back(self.root_id()); let tree = self.tree_ref(); @@ -412,8 +427,14 @@ impl RealDom { } } + /// Traverses the dom in a breadth first manner, calling the provided function on each node. + pub fn traverse_breadth_first(&self, f: impl FnMut(NodeRef)) { + self.traverse_breadth_first_advanced(true, f); + } + /// Traverses the dom in a depth first manner mutably, calling the provided function on each node. - pub fn traverse_depth_first_mut( + /// If `enter_shadow_dom` is true, then the traversal will enter shadow doms in the tree. + pub fn traverse_depth_first_mut_advanced( &mut self, enter_shadow_doms: bool, mut f: impl FnMut(NodeMut), @@ -432,8 +453,14 @@ impl RealDom { } } + /// Traverses the dom in a depth first manner mutably, calling the provided function on each node. + pub fn traverse_depth_first_mut(&mut self, f: impl FnMut(NodeMut)) { + self.traverse_depth_first_mut_advanced(true, f) + } + /// Traverses the dom in a breadth first manner mutably, calling the provided function on each node. - pub fn traverse_breadth_first_mut( + /// If `enter_shadow_dom` is true, then the traversal will enter shadow doms in the tree. + pub fn traverse_breadth_first_mut_advanced( &mut self, enter_shadow_doms: bool, mut f: impl FnMut(NodeMut), @@ -453,6 +480,11 @@ impl RealDom { } } + /// Traverses the dom in a breadth first manner mutably, calling the provided function on each node. + pub fn traverse_breadth_first_mut(&mut self, f: impl FnMut(NodeMut)) { + self.traverse_breadth_first_mut_advanced(true, f); + } + /// Adds a [`NodeWatcher`] to the dom. Node watchers are called whenever a node is created or removed. pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher + 'static + Send + Sync) { self.node_watchers.write().unwrap().push(Box::new(watcher)); @@ -481,11 +513,11 @@ impl RealDom { /// Registers a new custom element. pub fn register_custom_element>(&mut self) { - self.register_custom_element_factory::() + self.register_custom_element_with_factory::() } /// Registers a new custom element with a custom factory. - pub fn register_custom_element_factory(&mut self) + pub fn register_custom_element_with_factory(&mut self) where F: CustomElementFactory, U: CustomElementUpdater, @@ -563,6 +595,14 @@ pub trait NodeImmutable: Sized { .then(|| ViewEntry::new(view, self.id())) } + /// Get the ids of the children of the current node, if enter_shadow_dom is true and the current node is a shadow slot, the ids of the nodes under the node the shadow slot is attached to will be returned + #[inline] + fn children_ids_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Vec { + self.real_dom() + .tree_ref() + .children_ids_advanced(id, enter_shadow_dom) + } + /// Get the ids of the children of the current node #[inline] fn child_ids(&self) -> Vec { @@ -581,6 +621,14 @@ pub trait NodeImmutable: Sized { .collect() } + /// Get the id of the parent of the current node, if enter_shadow_dom is true and the current node is a shadow root, the node the shadow root is attached to will be returned + #[inline] + fn parent_id_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Option { + self.real_dom() + .tree_ref() + .parent_id_advanced(id, enter_shadow_dom) + } + /// Get the id of the parent of the current node #[inline] fn parent_id(&self) -> Option { diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 1f26dc6a7..3f3777607 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -4,10 +4,10 @@ use crate::NodeId; use shipyard::{Component, EntitiesViewMut, Get, View, ViewMut}; use std::fmt::Debug; -/// A shadow_tree of a tree. +/// A shadow tree reference inside of a tree. This tree is isolated from the main tree. #[derive(PartialEq, Eq, Clone, Debug, Component)] pub struct ShadowTree { - /// The root of the shadow_tree + /// The root of the shadow tree pub shadow_roots: Vec, /// The node that children of the super tree should be inserted under. pub slot: Option, @@ -22,7 +22,7 @@ pub struct Node { /// If this node is a slot in a shadow_tree, this is node whose child_subtree is that shadow_tree. slot_for_light_tree: Option, /// If this node is a root of a shadow_tree, this is the node whose child_subtree is that shadow_tree. - light_tree_root: Option, + root_for_light_tree: Option, height: u16, } @@ -37,8 +37,8 @@ pub trait TreeRef { #[inline] fn parent_id_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Option { // If this node is the root of a shadow_tree, return the node the shadow_tree is attached - let light_tree_root = self.light_tree_root(id); - match (light_tree_root, enter_shadow_dom) { + let root_for_light_tree = self.root_for_light_tree(id); + match (root_for_light_tree, enter_shadow_dom) { (Some(id), true) => Some(id), _ => { let parent_id = self.parent_id(id); @@ -74,11 +74,10 @@ pub trait TreeRef { fn children_ids(&self, id: NodeId) -> Vec; /// The shadow tree tree under the node. fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree>; - // TODO: rethink naming /// The node that contains the shadow tree this node is a slot for fn slot_for_light_tree(&self, id: NodeId) -> Option; /// The node that contains the shadow tree this node is a root of - fn light_tree_root(&self, id: NodeId) -> Option; + fn root_for_light_tree(&self, id: NodeId) -> Option; /// The height of the node. fn height(&self, id: NodeId) -> Option; /// Returns true if the node exists. @@ -132,8 +131,8 @@ impl<'a> TreeRef for TreeRefView<'a> { self.get(id).ok()?.slot_for_light_tree } - fn light_tree_root(&self, id: NodeId) -> Option { - self.get(id).ok()?.light_tree_root + fn root_for_light_tree(&self, id: NodeId) -> Option { + self.get(id).ok()?.root_for_light_tree } } @@ -151,14 +150,14 @@ impl<'a> TreeMut for TreeMutView<'a> { // If this node is a slot in a shadow_tree, remove it from the shadow_tree. if let Some(light_tree) = light_tree { - let light_tree_root = (&mut tree.1).get(light_tree).unwrap(); + let root_for_light_tree = (&mut tree.1).get(light_tree).unwrap(); - if let Some(shadow_tree) = &mut light_tree_root.child_subtree { + if let Some(shadow_tree) = &mut root_for_light_tree.child_subtree { shadow_tree.slot = None; } debug_assert!( - light_tree_root.children.is_empty(), + root_for_light_tree.children.is_empty(), "ShadowTree root should have no children when slot is removed." ); } @@ -186,7 +185,7 @@ impl<'a> TreeMut for TreeMutView<'a> { height: 0, child_subtree: None, slot_for_light_tree: None, - light_tree_root: None, + root_for_light_tree: None, }, ); } @@ -283,7 +282,7 @@ impl<'a> TreeMut for TreeMutView<'a> { // Now that we have created the shadow_tree, we need to update the height of the shadow_tree roots for root in shadow_roots { - (&mut self.1).get(root).unwrap().light_tree_root = Some(id); + (&mut self.1).get(root).unwrap().root_for_light_tree = Some(id); set_height(self, root, light_root_height + 1); } } @@ -403,9 +402,9 @@ impl<'a> TreeRef for TreeMutView<'a> { node_data.get(id).ok()?.slot_for_light_tree } - fn light_tree_root(&self, id: NodeId) -> Option { + fn root_for_light_tree(&self, id: NodeId) -> Option { let node_data = &self.1; - node_data.get(id).ok()?.light_tree_root + node_data.get(id).ok()?.root_for_light_tree } } diff --git a/packages/native-core/tests/called_minimally_on_build.rs b/packages/native-core/tests/called_minimally_on_build.rs index f4e8cf6e1..3fa789a6c 100644 --- a/packages/native-core/tests/called_minimally_on_build.rs +++ b/packages/native-core/tests/called_minimally_on_build.rs @@ -146,7 +146,7 @@ macro_rules! test_state{ dioxus_state.apply_mutations(&mut dom, mutations); dom.update_state(SendAnyMap::new()); - dom.traverse_depth_first(false, |n| { + dom.traverse_depth_first_advanced(false, |n| { $( assert_eq!(n.get::<$state>().unwrap().0, 1); )* diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs index 7bddeacc9..935ac94d0 100644 --- a/packages/native-core/tests/custom_element.rs +++ b/packages/native-core/tests/custom_element.rs @@ -301,7 +301,7 @@ fn custom_elements_work() { rdom.update_state(ctx); // render... - rdom.traverse_depth_first(true, |node| { + rdom.traverse_depth_first_advanced(true, |node| { let node_type = &*node.node_type(); let height = node.height() as usize; let indent = " ".repeat(height); diff --git a/packages/rink/src/focus.rs b/packages/rink/src/focus.rs index 4ede95485..e26f79b3d 100644 --- a/packages/rink/src/focus.rs +++ b/packages/rink/src/focus.rs @@ -183,7 +183,7 @@ impl FocusState { if forward { // find the closest focusable element after the current level - rdom.traverse_depth_first(true, |n| { + rdom.traverse_depth_first(|n| { let node_level = n.get::().unwrap().level; if node_level != *focus_level && node_level.focusable() @@ -200,7 +200,7 @@ impl FocusState { }); } else { // find the closest focusable element before the current level - rdom.traverse_depth_first(true, |n| { + rdom.traverse_depth_first(|n| { let node_level = n.get::().unwrap().level; if node_level != *focus_level && node_level.focusable() diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index b54cc2eaf..55a9274aa 100644 --- a/packages/rink/src/hooks.rs +++ b/packages/rink/src/hooks.rs @@ -550,7 +550,7 @@ impl InnerInputState { // update focus if was_released { let mut focus_id = None; - dom.traverse_depth_first(true, |node| { + dom.traverse_depth_first(|node| { let node_layout = layout .layout(node.get::().unwrap().node.unwrap()) .unwrap(); From 5d9d9e744167332bd90e8fca418a6af85d1c8e4a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 17 Apr 2023 13:44:44 -0500 Subject: [PATCH 443/895] fix clippy --- packages/native-core/tests/custom_element.rs | 27 +++++++++----------- packages/rink/examples/widgets.rs | 13 ++++------ 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/packages/native-core/tests/custom_element.rs b/packages/native-core/tests/custom_element.rs index 935ac94d0..e875342d9 100644 --- a/packages/native-core/tests/custom_element.rs +++ b/packages/native-core/tests/custom_element.rs @@ -309,24 +309,21 @@ fn custom_elements_work() { let size = *node.get::().unwrap(); let id = node.id(); println!("{indent}{id:?} {color:?} {size:?} {node_type:?}"); - match node_type { - NodeType::Element(el) => { - match el.tag.as_str() { - // the color should bubble up from customelementslot - "testing132" | "customelementslot" => { - assert_eq!(color.color, 1); - } - // the color of the light dom should not effect the color of the shadow dom, so the color of divs in the shadow dom should be 0 - "div" => { - assert_eq!(color.color, 0); - } - _ => {} + if let NodeType::Element(el) = node_type { + match el.tag.as_str() { + // the color should bubble up from customelementslot + "testing132" | "customelementslot" => { + assert_eq!(color.color, 1); } - if el.tag != "Root" { - assert_eq!(size.size, (i + 2).saturating_sub(height)); + // the color of the light dom should not effect the color of the shadow dom, so the color of divs in the shadow dom should be 0 + "div" => { + assert_eq!(color.color, 0); } + _ => {} + } + if el.tag != "Root" { + assert_eq!(size.size, (i + 2).saturating_sub(height)); } - _ => {} } }); } diff --git a/packages/rink/examples/widgets.rs b/packages/rink/examples/widgets.rs index 1226d5c3d..b39a3b4c2 100644 --- a/packages/rink/examples/widgets.rs +++ b/packages/rink/examples/widgets.rs @@ -76,16 +76,13 @@ impl Driver for Counter { event: Rc, _: bool, ) { - match event_type { - "input" => { - // when the button is clicked, increment the counter - if let EventData::Form(input_event) = &*event { - if let Ok(value) = input_event.value.parse::() { - self.count = value; - } + if event_type == "input" { + // when the button is clicked, increment the counter + if let EventData::Form(input_event) = &*event { + if let Ok(value) = input_event.value.parse::() { + self.count = value; } } - _ => {} } } From bed1d58a77f420a1c0f7303f1c48fcfbe0c6e5ac Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 18 Apr 2023 09:24:34 -0500 Subject: [PATCH 444/895] create web file engine --- packages/web/Cargo.toml | 4 ++ packages/web/src/dom.rs | 20 +++++-- packages/web/src/file_engine.rs | 103 ++++++++++++++++++++++++++++++++ packages/web/src/lib.rs | 1 + 4 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 packages/web/src/file_engine.rs diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 7adfbf13a..fcbb996bb 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -32,6 +32,7 @@ futures-channel = "0.3.21" serde_json = { version = "1.0" } serde = { version = "1.0" } serde-wasm-bindgen = "0.4.5" +async-trait = "0.1.58" [dependencies.web-sys] version = "0.3.56" @@ -76,6 +77,9 @@ features = [ "Location", "MessageEvent", "console", + "FileList", + "File", + "FileReader" ] [features] diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 4d17749d8..e792c977d 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -10,15 +10,15 @@ use dioxus_core::{ BorrowedAttributeValue, ElementId, Mutation, Template, TemplateAttribute, TemplateNode, }; -use dioxus_html::{event_bubbles, CompositionData, FormData}; +use dioxus_html::{event_bubbles, CompositionData, FileEngine, FormData}; use dioxus_interpreter_js::{save_template, Channel}; use futures_channel::mpsc; use rustc_hash::FxHashMap; -use std::{any::Any, rc::Rc}; +use std::{any::Any, rc::Rc, sync::Arc}; use wasm_bindgen::{closure::Closure, JsCast}; -use web_sys::{Document, Element, Event, HtmlElement}; +use web_sys::{console, Document, Element, Event, HtmlElement}; -use crate::Config; +use crate::{file_engine::WebFileEngine, Config}; pub struct WebsysDom { document: Document, @@ -206,6 +206,7 @@ impl WebsysDom { }, SetText { value, id } => i.set_text(id.0 as u32, value), NewEventListener { name, id, .. } => { + console::log_1(&format!("new event listener: {}", name).into()); i.new_event_listener(name, id.0 as u32, event_bubbles(name) as u8); } RemoveEventListener { name, id } => { @@ -224,6 +225,7 @@ impl WebsysDom { // We need tests that simulate clicks/etc and make sure every event type works. pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -> Rc { use dioxus_html::events::*; + console::log_1(&event.clone().into()); match event.type_().as_str() { "copy" | "cut" | "paste" => Rc::new(ClipboardData {}), @@ -359,10 +361,18 @@ fn read_input_to_data(target: Element) -> Rc { } } + let files = target + .dyn_ref() + .and_then(|input: &web_sys::HtmlInputElement| { + input.files().and_then(|files| { + WebFileEngine::new(files).map(|f| Arc::new(f) as Arc) + }) + }); + Rc::new(FormData { value, values, - files: None, + files, }) } diff --git a/packages/web/src/file_engine.rs b/packages/web/src/file_engine.rs new file mode 100644 index 000000000..6552be084 --- /dev/null +++ b/packages/web/src/file_engine.rs @@ -0,0 +1,103 @@ +use dioxus_html::FileEngine; +use futures_channel::oneshot; +use js_sys::Uint8Array; +use wasm_bindgen::{prelude::Closure, JsCast}; +use web_sys::{File, FileList, FileReader}; + +pub(crate) struct WebFileEngine { + file_reader: FileReader, + file_list: FileList, +} + +impl WebFileEngine { + pub fn new(file_list: FileList) -> Option { + Some(Self { + file_list, + file_reader: FileReader::new().ok()?, + }) + } + + fn len(&self) -> usize { + self.file_list.length() as usize + } + + fn get(&self, index: usize) -> Option { + self.file_list.item(index as u32) + } + + fn find(&self, name: &str) -> Option { + (0..self.len()) + .filter_map(|i| self.get(i)) + .find(|f| f.name() == name) + } +} + +#[async_trait::async_trait(?Send)] +impl FileEngine for WebFileEngine { + fn files(&self) -> Vec { + (0..self.len()) + .filter_map(|i| self.get(i).map(|f| f.name())) + .collect() + } + + // read a file to bytes + async fn read_file(&self, file: &str) -> Option> { + let file = self.find(file)?; + + let file_reader = self.file_reader.clone(); + let (rx, tx) = oneshot::channel(); + let on_load: Closure = Closure::new({ + let mut rx = Some(rx); + move || { + let result = file_reader.result(); + let _ = rx + .take() + .expect("multiple files read without refreshing the channel") + .send(result); + } + }); + + self.file_reader + .set_onload(Some(on_load.as_ref().unchecked_ref())); + on_load.forget(); + self.file_reader.read_as_array_buffer(&file).ok()?; + + if let Ok(Ok(js_val)) = tx.await { + let as_u8_arr = Uint8Array::new(&js_val); + let as_u8_vec = as_u8_arr.to_vec(); + + Some(as_u8_vec) + } else { + None + } + } + + // read a file to string + async fn read_file_to_string(&self, file: &str) -> Option { + let file = self.find(file)?; + + let file_reader = self.file_reader.clone(); + let (rx, tx) = oneshot::channel(); + let on_load: Closure = Closure::new({ + let mut rx = Some(rx); + move || { + let result = file_reader.result(); + let _ = rx + .take() + .expect("multiple files read without refreshing the channel") + .send(result); + } + }); + + self.file_reader + .set_onload(Some(on_load.as_ref().unchecked_ref())); + on_load.forget(); + self.file_reader.read_as_text(&file).ok()?; + + if let Ok(Ok(js_val)) = tx.await { + js_val.as_string() + } else { + None + } + } +} diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index e208b0591..14705b85a 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -61,6 +61,7 @@ use futures_util::{pin_mut, FutureExt, StreamExt}; mod cache; mod cfg; mod dom; +mod file_engine; mod hot_reload; #[cfg(feature = "hydrate")] mod rehydrate; From 8669a5eb0e154a861ab4b9f67df1e859401ee783 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 20 Apr 2023 08:55:35 -0500 Subject: [PATCH 445/895] remove unused shipyard-heigharchy --- packages/native-core/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 9ea6d4c9f..c9be2f27d 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -29,7 +29,6 @@ lightningcss = "1.0.0-alpha.39" rayon = "1.6.1" shipyard = { version = "0.6.2", features = ["proc", "std"], default-features = false } -shipyard_hierarchy = "0.6.0" [dev-dependencies] rand = "0.8.5" From d7eae795094f810d27833f3efd0d22696f347a42 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 20 Apr 2023 10:10:52 -0500 Subject: [PATCH 446/895] prevent default file input behavior on desktop --- packages/desktop/src/protocol.rs | 18 +- packages/interpreter/src/interpreter.js | 208 ++++++++++++------------ 2 files changed, 124 insertions(+), 102 deletions(-) diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index efdc849a5..3d4246987 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -9,10 +9,26 @@ use wry::{ }; fn module_loader(root_name: &str) -> String { + let js = INTERPRETER_JS.replace( + "/*POST_HANDLE_EDITS*/", + r#"// Prevent file inputs from opening the file dialog on click + let inputs = document.querySelectorAll("input"); + for (let input of inputs) { + input.addEventListener("click", (event) => { + let target = event.target; + // prevent file inputs from opening the file dialog on click + const type = target.getAttribute("type"); + if (type === "file") { + window.ipc.postMessage(serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple") })); + event.preventDefault(); + } + }); + }"#, + ); format!( r#" diff --git a/packages/interpreter/src/bindings.rs b/packages/interpreter/src/bindings.rs index 478b8ca5c..4fd9016f1 100644 --- a/packages/interpreter/src/bindings.rs +++ b/packages/interpreter/src/bindings.rs @@ -6,10 +6,14 @@ use web_sys::Element; #[wasm_bindgen(module = "/src/interpreter.js")] extern "C" { + pub type InterpreterConfig; + #[wasm_bindgen(constructor)] + pub fn new(intercept_link_redirects: bool) -> InterpreterConfig; + pub type Interpreter; #[wasm_bindgen(constructor)] - pub fn new(arg: Element) -> Interpreter; + pub fn new(arg: Element, config: InterpreterConfig) -> Interpreter; #[wasm_bindgen(method)] pub fn SaveTemplate(this: &Interpreter, template: JsValue); diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index b921c7c22..df9dd85e0 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -17,8 +17,7 @@ class ListenerMap { } else { this.global[event_name].active++; } - } - else { + } else { const id = element.getAttribute("data-dioxus-id"); if (!this.local[id]) { this.local[id] = {}; @@ -32,11 +31,13 @@ class ListenerMap { if (bubbles) { this.global[event_name].active--; if (this.global[event_name].active === 0) { - this.root.removeEventListener(event_name, this.global[event_name].callback); + this.root.removeEventListener( + event_name, + this.global[event_name].callback + ); delete this.global[event_name]; } - } - else { + } else { const id = element.getAttribute("data-dioxus-id"); delete this.local[id][event_name]; if (this.local[id].length === 0) { @@ -52,8 +53,15 @@ class ListenerMap { } } +class InterpreterConfig { + constructor(intercept_link_redirects) { + this.intercept_link_redirects = intercept_link_redirects; + } +} + class Interpreter { - constructor(root) { + constructor(root, config) { + this.config = config; this.root = root; this.listeners = new ListenerMap(root); this.nodes = [root]; @@ -143,8 +151,7 @@ class Interpreter { SetAttribute(id, field, value, ns) { if (value === null) { this.RemoveAttribute(id, field, ns); - } - else { + } else { const node = this.nodes[id]; this.SetAttributeInner(node, field, value, ns); } @@ -342,7 +349,6 @@ class Interpreter { this.RemoveEventListener(edit.id, edit.name); break; case "NewEventListener": - let bubbles = event_bubbles(edit.name); // this handler is only provided on desktop implementations since this @@ -357,15 +363,21 @@ class Interpreter { if (event.type === "click") { // todo call prevent default if it's the right type of event - let a_element = target.closest("a"); - if (a_element != null) { - event.preventDefault(); - if (shouldPreventDefault !== `onclick` && a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`) { - const href = a_element.getAttribute("href"); - if (href !== "" && href !== null && href !== undefined) { - window.ipc.postMessage( - serializeIpcMessage("browser_open", { href }) - ); + if (this.config.intercept_link_redirects) { + let a_element = target.closest("a"); + if (a_element != null) { + event.preventDefault(); + if ( + shouldPreventDefault !== `onclick` && + a_element.getAttribute(`dioxus-prevent-default`) !== + `onclick` + ) { + const href = a_element.getAttribute("href"); + if (href !== "" && href !== null && href !== undefined) { + window.ipc.postMessage( + serializeIpcMessage("browser_open", { href }) + ); + } } } } diff --git a/packages/liveview/src/main.js b/packages/liveview/src/main.js index 7dd9758d6..a3e5136ca 100644 --- a/packages/liveview/src/main.js +++ b/packages/liveview/src/main.js @@ -8,7 +8,7 @@ function main() { class IPC { constructor(root) { // connect to the websocket - window.interpreter = new Interpreter(root); + window.interpreter = new Interpreter(root, new InterpreterConfig(false)); let ws = new WebSocket(WS_ADDR); From 459d8d69a7c35f3c9d3dc3df8171b2daf14fe422 Mon Sep 17 00:00:00 2001 From: Antonio Curavalea Date: Mon, 24 Apr 2023 02:26:23 +0300 Subject: [PATCH 454/895] examples: add PWA w/ Dioxus CLI template (#977) * examples: add PWA w/ Dioxus CLI template * ci: properly set workspace and dependencies --- Cargo.toml | 1 + examples/PWA-example/Cargo.toml | 17 ++ examples/PWA-example/Dioxus.toml | 42 +++++ examples/PWA-example/LICENSE | 21 +++ examples/PWA-example/README.md | 44 +++++ examples/PWA-example/index.html | 30 ++++ examples/PWA-example/public/favicon.ico | Bin 0 -> 23104 bytes examples/PWA-example/public/logo_192.png | Bin 0 -> 11198 bytes examples/PWA-example/public/logo_512.png | Bin 0 -> 48151 bytes examples/PWA-example/public/manifest.json | 34 ++++ examples/PWA-example/public/sw.js | 198 ++++++++++++++++++++++ examples/PWA-example/src/main.rs | 20 +++ 12 files changed, 407 insertions(+) create mode 100644 examples/PWA-example/Cargo.toml create mode 100644 examples/PWA-example/Dioxus.toml create mode 100644 examples/PWA-example/LICENSE create mode 100644 examples/PWA-example/README.md create mode 100644 examples/PWA-example/index.html create mode 100644 examples/PWA-example/public/favicon.ico create mode 100644 examples/PWA-example/public/logo_192.png create mode 100644 examples/PWA-example/public/logo_512.png create mode 100644 examples/PWA-example/public/manifest.json create mode 100644 examples/PWA-example/public/sw.js create mode 100644 examples/PWA-example/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 7b6a08a39..377ff37b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ members = [ "packages/signals", "packages/hot-reload", "docs/guide", + "examples/PWA-example", ] # This is a "virtual package" diff --git a/examples/PWA-example/Cargo.toml b/examples/PWA-example/Cargo.toml new file mode 100644 index 000000000..f11d80713 --- /dev/null +++ b/examples/PWA-example/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dioxus-pwa-example" +version = "0.1.0" +authors = ["Antonio Curavalea "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { path = "../../packages/dioxus", version = "^0.3.0"} +dioxus-web = { path = "../../packages/web", version = "^0.3.0"} + +log = "0.4.6" + +# WebAssembly Debug +wasm-logger = "0.2.0" +console_error_panic_hook = "0.1.7" diff --git a/examples/PWA-example/Dioxus.toml b/examples/PWA-example/Dioxus.toml new file mode 100644 index 000000000..e3a472520 --- /dev/null +++ b/examples/PWA-example/Dioxus.toml @@ -0,0 +1,42 @@ +[application] + +# App (Project) Name +name = "dioxus-pwa-example" + +# Dioxus App Default Platform +# desktop, web, mobile, ssr +default_platform = "web" + +# `build` & `serve` dist path +out_dir = "dist" + +# resource (public) file folder +asset_dir = "public" + +[web.app] + +# HTML title tag content +title = "dioxus | ⛺" + +[web.watcher] + +# when watcher trigger, regenerate the `index.html` +reload_html = true + +# which files or dirs will be watcher monitoring +watch_path = ["src", "public"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [] diff --git a/examples/PWA-example/LICENSE b/examples/PWA-example/LICENSE new file mode 100644 index 000000000..bcdd828e9 --- /dev/null +++ b/examples/PWA-example/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Dioxus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/PWA-example/README.md b/examples/PWA-example/README.md new file mode 100644 index 000000000..dfd986302 --- /dev/null +++ b/examples/PWA-example/README.md @@ -0,0 +1,44 @@ +# Dioxus PWA example + +This is a basic example of a progressive web app (PWA) using Dioxus and Dioxus CLI. +Currently PWA functionality requires the use of a service worker and manifest file, so this isn't 100% Rust yet. + +It is also very much usable as a template for your projects, if you're aiming to create a PWA. + +## Try the example + +Make sure you have Dioxus CLI installed (if you're unsure, run `cargo install dioxus-cli`). + +You can run `dioxus serve` in this directory to start the web server locally, or run +`dioxus build --release` to build the project so you can deploy it on a separate web-server. + +## Project Structure +``` +├── Cargo.toml +├── Dioxus.toml +├── index.html // Custom HTML is needed for this, to load the SW and manifest. +├── LICENSE +├── public +│ ├── favicon.ico +│ ├── logo_192.png +│ ├── logo_512.png +│ ├── manifest.json // The manifest file - edit this as you need to. +│ └── sw.js // The service worker - you must edit this for actual projects. +├── README.md +└── src + └── main.rs +``` + +## Resources + +If you're just getting started with PWAs, here are some useful resources: + +* [PWABuilder docs](https://docs.pwabuilder.com/#/) +* [MDN article on PWAs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) + +For service worker scripting (in JavaScript): + +* [Service worker guide from PWABuilder](https://docs.pwabuilder.com/#/home/sw-intro) +* [Service worker examples, also from PWABuilder](https://github.com/pwa-builder/pwabuilder-serviceworkers) + +If you want to stay as close to 100% Rust as possible, you can try using [wasi-worker](https://github.com/dunnock/wasi-worker) to replace the JS service worker file. The JSON manifest will still be required though. \ No newline at end of file diff --git a/examples/PWA-example/index.html b/examples/PWA-example/index.html new file mode 100644 index 000000000..44bfa59cc --- /dev/null +++ b/examples/PWA-example/index.html @@ -0,0 +1,30 @@ + + + + {app_title} + + + + + + {style_include} + + +

+ + {script_include} + + \ No newline at end of file diff --git a/examples/PWA-example/public/favicon.ico b/examples/PWA-example/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b11015bdbacdb3b99e03555edb85d78467b37c7d GIT binary patch literal 23104 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 W+`s-{ME)24jHW23DqAIO8vH-~t)grI literal 0 HcmV?d00001 diff --git a/examples/PWA-example/public/logo_192.png b/examples/PWA-example/public/logo_192.png new file mode 100644 index 0000000000000000000000000000000000000000..112eb5ee49ca4e69d742a99269d1ae08a970dd7a GIT binary patch literal 11198 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 literal 0 HcmV?d00001 diff --git a/examples/PWA-example/public/logo_512.png b/examples/PWA-example/public/logo_512.png new file mode 100644 index 0000000000000000000000000000000000000000..43129772a892a5ca82dfdc8bb4d9027cc830ddf5 GIT binary patch literal 48151 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 Unavailable', { + status: 503, + statusText: 'Service Unavailable', + headers: new Headers({ + 'Content-Type': 'text/html' + }) + }); + } + }) + ); +}); + +/* The activate event fires after a service worker has been successfully installed. + It is most useful when phasing out an older version of a service worker, as at + this point you know that the new worker was installed correctly. In this example, + we delete old caches that don't match the version in the worker we just finished + installing. +*/ +self.addEventListener("activate", function (event) { + /* Just like with the install event, event.waitUntil blocks activate on a promise. + Activation will fail unless the promise is fulfilled. + */ + //console.log('WORKER: activate event in progress.'); + + event.waitUntil( + caches + /* This method returns a promise which will resolve to an array of available + cache keys. + */ + .keys() + .then(function (keys) { + // We return a promise that settles when all outdated caches are deleted. + return Promise.all( + keys + .filter(function (key) { + // Filter by keys that don't start with the latest version prefix. + return !key.startsWith(version); + }) + .map(function (key) { + /* Return a promise that's fulfilled + when each outdated cache is deleted. + */ + return caches.delete(key); + }) + ); + }) + .then(function () { + //console.log('WORKER: activate completed.'); + }) + ); +}); diff --git a/examples/PWA-example/src/main.rs b/examples/PWA-example/src/main.rs new file mode 100644 index 000000000..4c09a9bc5 --- /dev/null +++ b/examples/PWA-example/src/main.rs @@ -0,0 +1,20 @@ +use dioxus::prelude::*; + +fn main() { + // init debug tool for WebAssembly + wasm_logger::init(wasm_logger::Config::default()); + console_error_panic_hook::set_once(); + + dioxus_web::launch(app); +} + +fn app(cx: Scope) -> Element { + cx.render(rsx! ( + div { + style: "text-align: center;", + h1 { "🌗 Dioxus 🚀" } + h3 { "Frontend that scales." } + p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." } + } + )) +} From 60eb453aada6b65c4857b28e48cd18afe8cedab8 Mon Sep 17 00:00:00 2001 From: Ell Date: Mon, 24 Apr 2023 15:40:00 +0500 Subject: [PATCH 455/895] Made clone_repo error clear. --- src/cli/translate/mod.rs | 4 +--- src/tools.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cli/translate/mod.rs b/src/cli/translate/mod.rs index 20ca724fd..3056a6c77 100644 --- a/src/cli/translate/mod.rs +++ b/src/cli/translate/mod.rs @@ -1,8 +1,6 @@ use std::process::exit; -use dioxus_rsx::{BodyNode, CallBody, Component}; -use proc_macro2::{Ident, Span}; -use syn::punctuated::Punctuated; +use dioxus_rsx::{BodyNode, CallBody}; use super::*; diff --git a/src/tools.rs b/src/tools.rs index 704104de6..37ecc4e38 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -1,6 +1,6 @@ use std::{ fs::{create_dir_all, File}, - io::{Read, Write}, + io::{Read, Write, ErrorKind}, path::{Path, PathBuf}, process::Command, }; @@ -46,7 +46,13 @@ pub fn clone_repo(dir: &Path, url: &str) -> anyhow::Result<()> { let mut cmd = Command::new("git"); let cmd = cmd.current_dir(target_dir); - let _res = cmd.arg("clone").arg(url).arg(dir_name).output()?; + let res = cmd.arg("clone").arg(url).arg(dir_name).output(); + if let Err(err) = res { + if ErrorKind::NotFound == err.kind() { + log::error!("Git program not found. Hint: Install git or check $PATH."); + return Err(err.into()); + } + } Ok(()) } From 9f238fa464189483651a741c2331375d325d44cd Mon Sep 17 00:00:00 2001 From: Ell Date: Mon, 24 Apr 2023 20:34:17 +0500 Subject: [PATCH 456/895] Minor improvments. --- src/cli/plugin/mod.rs | 10 ++++++---- src/plugin/mod.rs | 10 ++++++---- src/tools.rs | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/cli/plugin/mod.rs b/src/cli/plugin/mod.rs index 9179f5bd6..ca2937306 100644 --- a/src/cli/plugin/mod.rs +++ b/src/cli/plugin/mod.rs @@ -21,10 +21,12 @@ impl Plugin { } } Plugin::AppPath {} => { - if let Some(v) = crate::plugin::PluginManager::init_plugin_dir().to_str() { - println!("{}", v); - } else { - log::error!("Plugin path get failed."); + if let Ok(plugin_dir) = crate::plugin::PluginManager::init_plugin_dir() { + if let Some(v) = plugin_dir.to_str() { + println!("{}", v); + } else { + log::error!("Plugin path get failed."); + } } } Plugin::Add { name: _ } => { diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index c75e96444..5648b395f 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -42,7 +42,7 @@ impl PluginManager { let manager = lua.create_table().unwrap(); let name_index = lua.create_table().unwrap(); - let plugin_dir = Self::init_plugin_dir(); + let plugin_dir = Self::init_plugin_dir().unwrap(); let api = lua.create_table().unwrap(); @@ -288,15 +288,17 @@ impl PluginManager { Ok(()) } - pub fn init_plugin_dir() -> PathBuf { + pub fn init_plugin_dir() -> anyhow::Result { let app_path = app_path(); let plugin_path = app_path.join("plugins"); if !plugin_path.is_dir() { log::info!("📖 Start to init plugin library ..."); let url = "https://github.com/DioxusLabs/cli-plugin-library"; - clone_repo(&plugin_path, url).unwrap(); + if let Err(err) = clone_repo(&plugin_path, url) { + log::error!("Failed to init plugin dir, error caused by {}. ", err); + } } - plugin_path + Ok(plugin_path) } pub fn plugin_list() -> Vec { diff --git a/src/tools.rs b/src/tools.rs index 37ecc4e38..f11befaf5 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -49,7 +49,7 @@ pub fn clone_repo(dir: &Path, url: &str) -> anyhow::Result<()> { let res = cmd.arg("clone").arg(url).arg(dir_name).output(); if let Err(err) = res { if ErrorKind::NotFound == err.kind() { - log::error!("Git program not found. Hint: Install git or check $PATH."); + log::warn!("Git program not found. Hint: Install git or check $PATH."); return Err(err.into()); } } From 61dba2825cf9430c8ebd0e6bdaeaa6fe2c2a4d7d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 24 Apr 2023 11:16:53 -0500 Subject: [PATCH 457/895] Improve the custom hooks chapter --- docs/guide/Cargo.toml | 6 +- docs/guide/examples/hooks_anti_patterns.rs | 38 +++++++++++ docs/guide/examples/hooks_composed.rs | 54 +++++++++++++++ docs/guide/examples/hooks_custom_logic.rs | 57 ++++++++++++++++ .../src/en/interactivity/custom_hooks.md | 65 +++++++++++++++++++ 5 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 docs/guide/examples/hooks_anti_patterns.rs create mode 100644 docs/guide/examples/hooks_custom_logic.rs diff --git a/docs/guide/Cargo.toml b/docs/guide/Cargo.toml index 227bdfa35..3919dc11c 100644 --- a/docs/guide/Cargo.toml +++ b/docs/guide/Cargo.toml @@ -16,12 +16,12 @@ dioxus-native-core-macro = { path = "../../packages/native-core-macro" } dioxus-router = { path = "../../packages/router" } dioxus-liveview = { path = "../../packages/liveview", features = ["axum"] } dioxus-tui = { path = "../../packages/dioxus-tui" } -fermi = { path = "../../packages/fermi" } -shipyard = "0.6.2" - # dioxus = { path = "../../packages/dioxus", features = ["desktop", "web", "ssr", "router", "fermi", "tui"] } +fermi = { path = "../../packages/fermi" } +shipyard = "0.6.2" serde = { version = "1.0.138", features=["derive"] } reqwest = { version = "0.11.11", features = ["json"] } tokio = { version = "1.19.2" , features=[]} axum = { version = "0.6.1", features = ["ws"] } +gloo-storage = "0.2.2" diff --git a/docs/guide/examples/hooks_anti_patterns.rs b/docs/guide/examples/hooks_anti_patterns.rs new file mode 100644 index 000000000..2119b8601 --- /dev/null +++ b/docs/guide/examples/hooks_anti_patterns.rs @@ -0,0 +1,38 @@ +#![allow(unused)] + +use dioxus::prelude::*; + +fn main() {} + +// ANCHOR: non_clone_state +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Arc; + +struct UseState<'a, T> { + value: &'a RefCell, + update: Arc, +} + +fn my_use_state(cx: &ScopeState, init: impl FnOnce() -> T) -> UseState { + // The update function will trigger a re-render in the component cx is attached to + let update = cx.schedule_update(); + // Create the initial state + let value = cx.use_hook(|| RefCell::new(init())); + + UseState { value, update } +} + +impl UseState<'_, T> { + fn get(&self) -> T { + self.value.borrow().clone() + } + + fn set(&self, value: T) { + // Update the state + *self.value.borrow_mut() = value; + // Trigger a re-render on the component the state is from + (self.update)(); + } +} +// ANCHOR_END: non_clone_state diff --git a/docs/guide/examples/hooks_composed.rs b/docs/guide/examples/hooks_composed.rs index 801474aa3..782a19d7d 100644 --- a/docs/guide/examples/hooks_composed.rs +++ b/docs/guide/examples/hooks_composed.rs @@ -11,3 +11,57 @@ fn use_settings(cx: &ScopeState) -> &UseSharedState { use_shared_state::(cx).expect("App settings not provided") } // ANCHOR_END: wrap_context + +// ANCHOR: use_storage +use gloo_storage::{LocalStorage, Storage}; +use serde::{de::DeserializeOwned, Serialize}; + +/// A persistent storage hook that can be used to store data across application reloads. +#[allow(clippy::needless_return)] +pub fn use_persistent( + cx: &ScopeState, + // A unique key for the storage entry + key: impl ToString, + // A function that returns the initial value if the storage entry is empty + init: impl FnOnce() -> T, +) -> &UsePersistent { + // Use the use_ref hook to create a mutable state for the storage entry + let state = use_ref(cx, move || { + // This closure will run when the hook is created + let key = key.to_string(); + let value = LocalStorage::get(key.as_str()).ok().unwrap_or_else(init); + StorageEntry { key, value } + }); + + // Wrap the state in a new struct with a custom API + // Note: We use use_hook here so that this hook is easier to use in closures in the rsx. Any values with the same lifetime as the ScopeState can be used in the closure without cloning. + cx.use_hook(|| UsePersistent { + inner: state.clone(), + }) +} + +struct StorageEntry { + key: String, + value: T, +} + +/// Storage that persists across application reloads +pub struct UsePersistent { + inner: UseRef>, +} + +impl UsePersistent { + /// Returns a reference to the value + pub fn get(&self) -> T { + self.inner.read().value.clone() + } + + /// Sets the value + pub fn set(&self, value: T) { + let mut inner = self.inner.write(); + // Write the new value to local storage + LocalStorage::set(inner.key.as_str(), &value); + inner.value = value; + } +} +// ANCHOR_END: use_storage diff --git a/docs/guide/examples/hooks_custom_logic.rs b/docs/guide/examples/hooks_custom_logic.rs new file mode 100644 index 000000000..2323ddb11 --- /dev/null +++ b/docs/guide/examples/hooks_custom_logic.rs @@ -0,0 +1,57 @@ +#![allow(unused)] + +use dioxus::prelude::*; + +fn main() {} + +// ANCHOR: use_state +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Arc; + +#[derive(Clone)] +struct UseState { + value: Rc>, + update: Arc, +} + +fn my_use_state(cx: &ScopeState, init: impl FnOnce() -> T) -> &UseState { + cx.use_hook(|| { + // The update function will trigger a re-render in the component cx is attached to + let update = cx.schedule_update(); + // Create the initial state + let value = Rc::new(RefCell::new(init())); + + UseState { value, update } + }) +} + +impl UseState { + fn get(&self) -> T { + self.value.borrow().clone() + } + + fn set(&self, value: T) { + // Update the state + *self.value.borrow_mut() = value; + // Trigger a re-render on the component the state is from + (self.update)(); + } +} +// ANCHOR_END: use_state + +// ANCHOR: use_context +pub fn use_context(cx: &ScopeState) -> Option<&T> { + cx.use_hook(|| cx.consume_context::()).as_ref() +} + +pub fn use_context_provider(cx: &ScopeState, f: impl FnOnce() -> T) -> &T { + cx.use_hook(|| { + let val = f(); + // Provide the context state to the scope + cx.provide_context(val.clone()); + val + }) +} + +// ANCHOR_END: use_context diff --git a/docs/guide/src/en/interactivity/custom_hooks.md b/docs/guide/src/en/interactivity/custom_hooks.md index 07472bb95..f3acec269 100644 --- a/docs/guide/src/en/interactivity/custom_hooks.md +++ b/docs/guide/src/en/interactivity/custom_hooks.md @@ -2,6 +2,8 @@ Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own. +When writing your hook, you can make a function that accepts `cx: &ScopeState` as a parameter to accept a scope with any Props. + ## Composing Hooks To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook. @@ -12,6 +14,12 @@ For example, if many components need to access an `AppSettings` struct, you can {{#include ../../../examples/hooks_composed.rs:wrap_context}} ``` +Or if you want to wrap a hook that persists reloads with the storage API, you can build on top of the use_ref hook to work with mutable state: + +```rust +{{#include ../../../examples/hooks_composed.rs:use_storage}} +``` + ## Custom Hook Logic You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.use_hook) to build your own hooks. In fact, this is what all the standard hooks are built on! @@ -23,4 +31,61 @@ You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct. Inside the initialization closure, you will typically make calls to other `cx` methods. For example: - The `use_state` hook tracks state in the hook value, and uses [`cx.schedule_update`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.schedule_update) to make Dioxus re-render the component whenever it changes. + +Here is a simplified implementation of the `use_state` hook: + +```rust +{{#include ../../../examples/hooks_custom_logic.rs:use_state}} +``` + - The `use_context` hook calls [`cx.consume_context`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.consume_context) (which would be expensive to call on every render) to get some context from the scope + +Here is an implementation of the `use_context` and `use_context_provider` hooks: + +```rust +{{#include ../../../examples/hooks_custom_logic.rs:use_context}} +``` + +## Hook Anti-Patterns + +When writing a custom hook, you should avoid the following anti-patterns: + +- !Clone Hooks: To allow hooks to be used within async blocks, the hooks must be Clone. To make a hook clone, you can wrap data in Rc or Arc and avoid lifetimes in hooks. + +This version of use_state may seem more efficient, but it is not cloneable: + +```rust +{{#include ../../../examples/hooks_anti_patterns.rs:non_clone_state}} +``` + +If we try to use this hook in an async block, we will get a compile error: + +```rust +fn FutureComponent(cx: &ScopeState) -> Element { + let my_state = my_use_state(cx, || 0); + cx.spawn({ + to_owned![my_state]; + async move { + my_state.set(1); + } + }); + + todo!() +} +``` + +But with the original version, we can use it in an async block: + +```rust +fn FutureComponent(cx: &ScopeState) -> Element { + let my_state = use_state(cx, || 0); + cx.spawn({ + to_owned![my_state]; + async move { + my_state.set(1); + } + }); + + todo!() +} +``` From bba7eaa61eea0ca22b1284431b062182403b313c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Z=C3=B6chbauer?= Date: Mon, 24 Apr 2023 18:22:32 +0200 Subject: [PATCH 458/895] Fix typo --- docs/src/cmd/serve.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/cmd/serve.md b/docs/src/cmd/serve.md index e5c10a902..4a699267b 100644 --- a/docs/src/cmd/serve.md +++ b/docs/src/cmd/serve.md @@ -45,5 +45,5 @@ You can use `--example {name}` to start a example code. ``` # build `example/test` code -dioxus serve --exmaple test -``` \ No newline at end of file +dioxus serve --example test +``` From eb4abca022ba10f6c3317f20a7165c8234675611 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 24 Apr 2023 11:48:52 -0500 Subject: [PATCH 459/895] update crossterm version --- packages/rink/Cargo.toml | 2 +- packages/rink/src/hooks.rs | 64 ++++++++++++++++++++++++++++++++++++-- packages/rink/src/lib.rs | 2 +- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/packages/rink/Cargo.toml b/packages/rink/Cargo.toml index 2f08eb720..e6af1ef98 100644 --- a/packages/rink/Cargo.toml +++ b/packages/rink/Cargo.toml @@ -18,7 +18,7 @@ dioxus-native-core = { path = "../native-core", version = "^0.2.0" } dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" } tui = "0.17.0" -crossterm = "0.23.0" +crossterm = "0.26.1" anyhow = "1.0.42" tokio = { version = "1.15.0", features = ["full"] } futures = "0.3.19" diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index fe29b4120..00bae0747 100644 --- a/packages/rink/src/hooks.rs +++ b/packages/rink/src/hooks.rs @@ -1,5 +1,6 @@ use crossterm::event::{ - Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind, + Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, ModifierKeyCode, MouseButton, + MouseEventKind, }; use dioxus_native_core::prelude::*; use dioxus_native_core::real_dom::NodeImmutable; @@ -800,6 +801,34 @@ fn key_from_crossterm_key_code(key_code: TermKeyCode) -> Key { TermKeyCode::Char(c) => Key::Character(c.to_string()), TermKeyCode::Null => Key::Unidentified, TermKeyCode::Esc => Key::Escape, + TermKeyCode::CapsLock => Key::CapsLock, + TermKeyCode::ScrollLock => Key::ScrollLock, + TermKeyCode::NumLock => Key::NumLock, + TermKeyCode::PrintScreen => Key::PrintScreen, + TermKeyCode::Pause => Key::Pause, + TermKeyCode::Media(crossterm::event::MediaKeyCode::FastForward) => Key::MediaFastForward, + TermKeyCode::Media(crossterm::event::MediaKeyCode::PlayPause) => Key::MediaPlayPause, + TermKeyCode::Media(crossterm::event::MediaKeyCode::TrackPrevious) => { + Key::MediaTrackPrevious + } + TermKeyCode::Media(crossterm::event::MediaKeyCode::TrackNext) => Key::MediaTrackNext, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Stop) => Key::MediaStop, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Play) => Key::MediaPlay, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Pause) => Key::MediaPause, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Record) => Key::MediaRecord, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Rewind) => Key::MediaRewind, + TermKeyCode::Modifier(modifier) => match modifier { + ModifierKeyCode::IsoLevel3Shift + | ModifierKeyCode::IsoLevel5Shift + | ModifierKeyCode::RightShift + | ModifierKeyCode::LeftShift => Key::Shift, + ModifierKeyCode::RightControl | ModifierKeyCode::LeftControl => Key::Control, + ModifierKeyCode::RightAlt | ModifierKeyCode::LeftAlt => Key::Alt, + ModifierKeyCode::RightSuper | ModifierKeyCode::LeftSuper => Key::Super, + ModifierKeyCode::RightHyper | ModifierKeyCode::LeftHyper => Key::Hyper, + ModifierKeyCode::LeftMeta | ModifierKeyCode::RightMeta => Key::Meta, + }, + _ => Key::Unidentified, } } @@ -929,8 +958,39 @@ fn guess_code_from_crossterm_key_code(key_code: TermKeyCode) -> Option { '~' => Code::Backquote, _ => return None, }, - TermKeyCode::Null => return None, TermKeyCode::Esc => Code::Escape, + TermKeyCode::CapsLock => Code::CapsLock, + TermKeyCode::ScrollLock => Code::ScrollLock, + TermKeyCode::NumLock => Code::NumLock, + TermKeyCode::PrintScreen => Code::PrintScreen, + TermKeyCode::Pause => Code::Pause, + TermKeyCode::Menu => Code::ContextMenu, + TermKeyCode::Media(crossterm::event::MediaKeyCode::FastForward) => Code::MediaFastForward, + TermKeyCode::Media(crossterm::event::MediaKeyCode::PlayPause) => Code::MediaPlayPause, + TermKeyCode::Media(crossterm::event::MediaKeyCode::TrackPrevious) => { + Code::MediaTrackPrevious + } + TermKeyCode::Media(crossterm::event::MediaKeyCode::TrackNext) => Code::MediaTrackNext, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Stop) => Code::MediaStop, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Play) => Code::MediaPlay, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Pause) => Code::MediaPause, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Record) => Code::MediaRecord, + TermKeyCode::Media(crossterm::event::MediaKeyCode::Rewind) => Code::MediaRewind, + TermKeyCode::Modifier(modifier) => match modifier { + ModifierKeyCode::IsoLevel3Shift + | ModifierKeyCode::IsoLevel5Shift + | ModifierKeyCode::LeftShift => Code::ShiftLeft, + ModifierKeyCode::RightShift => Code::ShiftRight, + ModifierKeyCode::RightControl => Code::ControlRight, + ModifierKeyCode::LeftControl => Code::ControlLeft, + ModifierKeyCode::RightAlt => Code::AltRight, + ModifierKeyCode::LeftAlt => Code::AltLeft, + ModifierKeyCode::RightSuper | ModifierKeyCode::LeftSuper => Code::Super, + ModifierKeyCode::RightHyper | ModifierKeyCode::LeftHyper => Code::Hyper, + ModifierKeyCode::LeftMeta => Code::MetaLeft, + ModifierKeyCode::RightMeta => Code::MetaRight, + }, + _ => return None, }; Some(code) diff --git a/packages/rink/src/lib.rs b/packages/rink/src/lib.rs index 9fceb6b48..5c7b644c0 100644 --- a/packages/rink/src/lib.rs +++ b/packages/rink/src/lib.rs @@ -234,7 +234,7 @@ pub fn render( } } TermEvent::Resize(_, _) => updated = true, - TermEvent::Mouse(_) => {} + _ => {} }, InputEvent::Close => break, }; From 7be8ec3467c497985d0b334536dcea61685f635c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 24 Apr 2023 16:07:50 -0500 Subject: [PATCH 460/895] Fix html to rsx conversions --- packages/autofmt/src/element.rs | 13 +++--- packages/rsx-rosetta/Cargo.toml | 3 ++ packages/rsx-rosetta/tests/simple.rs | 68 ++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 packages/rsx-rosetta/tests/simple.rs diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index 6d2cdc830..5bb7d42fc 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -276,13 +276,12 @@ impl Writer<'_> { let start = location.start(); let line_start = start.line - 1; - let this_line = self.src[line_start]; - - let beginning = if this_line.len() > start.column { - this_line[..start.column].trim() - } else { - "" - }; + let beginning = self + .src + .get(line_start) + .filter(|this_line| this_line.len() > start.column) + .map(|this_line| this_line[..start.column].trim()) + .unwrap_or_default(); beginning.is_empty() } diff --git a/packages/rsx-rosetta/Cargo.toml b/packages/rsx-rosetta/Cargo.toml index d160d2bf9..e6bc45225 100644 --- a/packages/rsx-rosetta/Cargo.toml +++ b/packages/rsx-rosetta/Cargo.toml @@ -25,3 +25,6 @@ convert_case = "0.5.0" # default = ["html"] # eventually more output options + +[dev-dependencies] +pretty_assertions = "1.2.1" \ No newline at end of file diff --git a/packages/rsx-rosetta/tests/simple.rs b/packages/rsx-rosetta/tests/simple.rs new file mode 100644 index 000000000..b8fd095e1 --- /dev/null +++ b/packages/rsx-rosetta/tests/simple.rs @@ -0,0 +1,68 @@ +use html_parser::Dom; + +#[test] +fn simple_elements() { + let html = r#" +
+
hello world!
+
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 { + div { class: "asd", "hello world!" } + div { id: "asd", "hello world!" } + 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); +} + +#[test] +fn deeply_nested() { + 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 { + div { class: "asd", + div { class: "asd", + div { class: "asd", div { class: "asd" } } + } + } + }"#; + pretty_assertions::assert_eq!(&out, &expected); +} From 8af3522a2e3f5094aedc9714521a1cd848530d9c Mon Sep 17 00:00:00 2001 From: Will Hopkins Date: Mon, 24 Apr 2023 14:13:54 -0700 Subject: [PATCH 461/895] fix: change crossterm poll timeout to 10ms from 1s (#983) Problem: Key events were delayed signifantly in TUI widgets. Solution: Decrease crossterm event poll timeout from 1000ms to 10ms. Fixes #978 --- packages/rink/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rink/src/lib.rs b/packages/rink/src/lib.rs index 9fceb6b48..7f15aa751 100644 --- a/packages/rink/src/lib.rs +++ b/packages/rink/src/lib.rs @@ -98,7 +98,8 @@ pub fn render( let event_tx_clone = event_tx.clone(); if !cfg.headless { std::thread::spawn(move || { - let tick_rate = Duration::from_millis(1000); + // Timeout after 10ms when waiting for events + let tick_rate = Duration::from_millis(10); loop { if crossterm::event::poll(tick_rate).unwrap() { let evt = crossterm::event::read().unwrap(); From b0a1f4773e93b902f2429527a15f78e946b30938 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 08:16:11 -0500 Subject: [PATCH 462/895] create file upload example --- examples/file_upload.rs | 37 +++++++++++++++++++++++++++++++++++++ packages/desktop/Cargo.toml | 3 ++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 examples/file_upload.rs diff --git a/examples/file_upload.rs b/examples/file_upload.rs new file mode 100644 index 000000000..c3771f7b0 --- /dev/null +++ b/examples/file_upload.rs @@ -0,0 +1,37 @@ +#![allow(non_snake_case)] +use dioxus::prelude::*; + +fn main() { + dioxus_desktop::launch(App); +} + +fn App(cx: Scope) -> Element { + let files_uploaded: &UseRef> = use_ref(cx, Vec::new); + + cx.render(rsx! { + input { + r#type: "file", + accept: "text/*", + onchange: |evt| { + to_owned![files_uploaded]; + async move { + println!("files uploaded: {:?}", evt); + if let Some(file_engine) = &evt.files { + let files = file_engine.files(); + for file_name in &files { + if let Some(file) = file_engine.read_file_to_string(&file_name).await{ + files_uploaded.write().push(file); + } + } + } + } + }, + } + + ul { + for file in files_uploaded.read().iter() { + li { "{file}" } + } + } + }) +} diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 5722a42a2..beb971ca9 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -23,12 +23,13 @@ thiserror = "1.0.30" log = "0.4.14" wry = { version = "0.27.2" } futures-channel = "0.3.21" -tokio = { version = "1.16.1", features = [ +tokio = { version = "1.27", features = [ "sync", "rt-multi-thread", "rt", "time", "macros", + "fs", ], optional = true, default-features = false } webbrowser = "0.8.0" infer = "0.11.0" From c1e2592299e0563cd0ef66626a44489c7ac6f0c4 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 09:26:56 -0500 Subject: [PATCH 463/895] implement file events on desktop --- examples/file_upload.rs | 4 +- packages/desktop/Cargo.toml | 3 +- packages/desktop/src/file_upload.rs | 74 +++++++++++++++++++++++++++++ packages/desktop/src/lib.rs | 28 ++++++++++- packages/desktop/src/protocol.rs | 28 +++++++---- 5 files changed, 123 insertions(+), 14 deletions(-) create mode 100644 packages/desktop/src/file_upload.rs diff --git a/examples/file_upload.rs b/examples/file_upload.rs index c3771f7b0..c43e6e6ef 100644 --- a/examples/file_upload.rs +++ b/examples/file_upload.rs @@ -11,11 +11,11 @@ fn App(cx: Scope) -> Element { cx.render(rsx! { input { r#type: "file", - accept: "text/*", + accept: ".txt", + multiple: true, onchange: |evt| { to_owned![files_uploaded]; async move { - println!("files uploaded: {:?}", evt); if let Some(file_engine) = &evt.files { let files = file_engine.files(); for file_name in &files { diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index beb971ca9..8b41019e1 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react"] [dependencies] dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] } -dioxus-html = { path = "../html", features = ["serialize"], version = "^0.3.0" } +dioxus-html = { path = "../html", features = ["serialize", "native-bind"], version = "^0.3.0" } dioxus-interpreter-js = { path = "../interpreter", version = "^0.3.0" } dioxus-hot-reload = { path = "../hot-reload", optional = true } @@ -37,6 +37,7 @@ dunce = "1.0.2" slab = "0.4" futures-util = "0.3.25" +rfd = "0.11.3" [target.'cfg(target_os = "ios")'.dependencies] objc = "0.2.7" diff --git a/packages/desktop/src/file_upload.rs b/packages/desktop/src/file_upload.rs new file mode 100644 index 000000000..ae4a81cc2 --- /dev/null +++ b/packages/desktop/src/file_upload.rs @@ -0,0 +1,74 @@ +use std::{path::PathBuf, str::FromStr}; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub(crate) struct FileDiologRequest { + accept: String, + multiple: bool, + pub event: String, + pub target: usize, + pub bubbles: bool, +} + +pub(crate) fn get_file_event(request: &FileDiologRequest) -> Vec { + let mut dialog = rfd::FileDialog::new(); + + let filters: Vec<_> = request + .accept + .split(',') + .filter_map(|s| Filters::from_str(s).ok()) + .collect(); + + let file_extensions: Vec<_> = filters + .iter() + .flat_map(|f| f.as_extensions().into_iter()) + .collect(); + + dialog = dialog.add_filter("name", file_extensions.as_slice()); + + let files: Vec<_> = if request.multiple { + dialog.pick_files().into_iter().flatten().collect() + } else { + dialog.pick_file().into_iter().collect() + }; + + files +} + +enum Filters { + Extension(String), + Mime(String), + Audio, + Video, + Image, +} + +impl Filters { + fn as_extensions(&self) -> Vec<&str> { + match self { + Filters::Extension(extension) => vec![extension.as_str()], + Filters::Mime(_) => vec![], + Filters::Audio => vec!["mp3", "wav", "ogg"], + Filters::Video => vec!["mp4", "webm"], + Filters::Image => vec!["png", "jpg", "jpeg", "gif", "webp"], + } + } +} + +impl FromStr for Filters { + type Err = String; + + fn from_str(s: &str) -> Result { + if let Some(extension) = s.strip_prefix('.') { + Ok(Filters::Extension(extension.to_string())) + } else { + match s { + "audio/*" => Ok(Filters::Audio), + "video/*" => Ok(Filters::Video), + "image/*" => Ok(Filters::Image), + _ => Ok(Filters::Mime(s.to_string())), + } + } + } +} diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index cdb592f72..4d904e948 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -8,6 +8,7 @@ mod desktop_context; mod escape; mod eval; mod events; +mod file_upload; mod protocol; mod shortcut; mod waker; @@ -19,14 +20,14 @@ pub use desktop_context::{ }; use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers}; use dioxus_core::*; -use dioxus_html::HtmlEvent; +use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent}; pub use eval::{use_eval, EvalResult}; use futures_util::{pin_mut, FutureExt}; use shortcut::ShortcutRegistry; pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; -use std::collections::HashMap; use std::rc::Rc; use std::task::Waker; +use std::{collections::HashMap, sync::Arc}; pub use tao::dpi::{LogicalSize, PhysicalSize}; use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget}; pub use tao::window::WindowBuilder; @@ -264,6 +265,29 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) } } + EventData::Ipc(msg) if msg.method() == "file_diolog" => { + if let Ok(file_diolog) = + serde_json::from_value::(msg.params()) + { + let id = ElementId(file_diolog.target); + let event_name = &file_diolog.event; + let event_bubbles = file_diolog.bubbles; + let files = file_upload::get_file_event(&file_diolog); + let data = FormData { + value: Default::default(), + values: Default::default(), + files: Some(Arc::new(NativeFileEngine::new(files))), + }; + + let view = webviews.get_mut(&event.1).unwrap(); + + view.dom + .handle_event(event_name, Rc::new(data), id, event_bubbles); + + send_edits(view.dom.render_immediate(), &view.webview); + } + } + _ => {} }, Event::GlobalShortcutEvent(id) => shortcut_manager.call_handlers(id), diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 3d4246987..5b0cd1cc7 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -14,15 +14,25 @@ fn module_loader(root_name: &str) -> String { r#"// Prevent file inputs from opening the file dialog on click let inputs = document.querySelectorAll("input"); for (let input of inputs) { - input.addEventListener("click", (event) => { - let target = event.target; - // prevent file inputs from opening the file dialog on click - const type = target.getAttribute("type"); - if (type === "file") { - window.ipc.postMessage(serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple") })); - event.preventDefault(); - } - }); + if (!input.getAttribute("data-dioxus-file-listener")) { + input.setAttribute("data-dioxus-file-listener", true); + input.addEventListener("click", (event) => { + let target = event.target; + // prevent file inputs from opening the file dialog on click + const type = target.getAttribute("type"); + if (type === "file") { + let target_id = find_real_id(target); + if (target_id !== null) { + const event_name = "change"; + const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); + console.log(message); + console.log(event); + window.ipc.postMessage(message); + } + event.preventDefault(); + } + }); + } }"#, ); format!( From 9cfb655478d3f12d18faaf9d955d8ca4739cf4b0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 14:26:12 -0500 Subject: [PATCH 464/895] implement the file engine for liveview --- packages/desktop/src/protocol.rs | 11 +++--- packages/html/src/events/form.rs | 47 +++++++++++++++++++++++- packages/interpreter/src/interpreter.js | 21 +++++++---- packages/liveview/Cargo.toml | 1 + packages/liveview/src/lib.rs | 49 ++++++++++++++++++++++++- 5 files changed, 113 insertions(+), 16 deletions(-) diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 5b0cd1cc7..f6725c428 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -23,11 +23,12 @@ fn module_loader(root_name: &str) -> String { if (type === "file") { let target_id = find_real_id(target); if (target_id !== null) { - const event_name = "change"; - const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); - console.log(message); - console.log(event); - window.ipc.postMessage(message); + const send = (event_name) => { + const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); + window.ipc.postMessage(message); + }; + send("change"); + send("input"); } event.preventDefault(); } diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 6edf60448..ec65ffe03 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -12,10 +12,55 @@ pub struct FormData { pub values: HashMap>, - #[cfg_attr(feature = "serialize", serde(skip))] + #[cfg_attr( + feature = "serialize", + serde(skip_serializing, deserialize_with = "deserialize_file_engine") + )] pub files: Option>, } +#[cfg(feature = "serialize")] +#[derive(serde::Serialize, serde::Deserialize)] +struct SerializedFileEngine { + files: HashMap>, +} + +#[cfg(feature = "serialize")] +#[async_trait::async_trait(?Send)] +impl FileEngine for SerializedFileEngine { + fn files(&self) -> Vec { + self.files.keys().cloned().collect() + } + + async fn read_file(&self, file: &str) -> Option> { + self.files.get(file).cloned() + } + + async fn read_file_to_string(&self, file: &str) -> Option { + self.read_file(file) + .await + .map(|bytes| String::from_utf8_lossy(&bytes).to_string()) + } +} + +#[cfg(feature = "serialize")] +fn deserialize_file_engine<'de, D>( + deserializer: D, +) -> Result>, D::Error> +where + D: serde::Deserializer<'de>, +{ + use serde::Deserialize; + + let Ok(file_engine) = + SerializedFileEngine::deserialize(deserializer) else{ + return Ok(None); + }; + + let file_engine = std::sync::Arc::new(file_engine); + Ok(Some(file_engine)) +} + impl PartialEq for FormData { fn eq(&self, other: &Self) -> bool { self.value == other.value && self.values == other.values diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index 162d5c8f5..81639b778 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -344,17 +344,19 @@ class Interpreter { this.RemoveEventListener(edit.id, edit.name); break; case "NewEventListener": - let bubbles = event_bubbles(edit.name); + const bubbles = event_bubbles(edit.name); - this.NewEventListener(edit.name, edit.id, bubbles, handler); + this.NewEventListener(edit.name, edit.id, bubbles, (event) => + handler(event, edit.name, bubbles) + ); break; } } } -// this handler is only provided on desktop implementations since this +// this handler is only provided on the desktop and liveview implementations since this // method is not used by the web implementation -function handler(event) { +function handler(event, name, bubbles) { let target = event.target; if (target != null) { let shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`); @@ -387,8 +389,6 @@ function handler(event) { shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`); - let contents = serialize_event(event); - if (shouldPreventDefault === `on${event.type}`) { event.preventDefault(); } @@ -397,6 +397,10 @@ function handler(event) { event.preventDefault(); } + let contents = serialize_event(event); + + /*POST_EVENT_SERIALIZATION*/ + if ( target.tagName === "FORM" && (event.type === "submit" || event.type === "input") @@ -408,7 +412,8 @@ function handler(event) { const formData = new FormData(target); for (let name of formData.keys()) { - contents.values[name] = formData.getAll(name); + let value = formData.getAll(name); + contents.values[name] = value; } } } @@ -418,7 +423,7 @@ function handler(event) { } window.ipc.postMessage( serializeIpcMessage("user_event", { - name: edit.name, + name: name, element: parseInt(realId), data: contents, bubbles, diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index 5269927b0..61fbe0887 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -36,6 +36,7 @@ axum = { version = "0.6.1", optional = true, features = ["ws"] } # salvo salvo = { version = "0.37.7", optional = true, features = ["ws"] } +once_cell = "1.17.1" # actix is ... complicated? # actix-files = { version = "0.6.2", optional = true } diff --git a/packages/liveview/src/lib.rs b/packages/liveview/src/lib.rs index ffddf0272..bea21a71b 100644 --- a/packages/liveview/src/lib.rs +++ b/packages/liveview/src/lib.rs @@ -34,7 +34,51 @@ pub enum LiveViewError { SendingFailed, } -use dioxus_interpreter_js::INTERPRETER_JS; +use once_cell::sync::Lazy; + +static INTERPRETER_JS: Lazy = Lazy::new(|| { + let interpreter = dioxus_interpreter_js::INTERPRETER_JS; + let serialize_file_uploads = r#"if ( + target.tagName === "INPUT" && + (event.type === "change" || event.type === "input") + ) { + const type = target.getAttribute("type"); + if (type === "file") { + async function read_files() { + const files = target.files; + const file_contents = {}; + + for (let i = 0; i < files.length; i++) { + const file = files[i]; + + file_contents[file.name] = Array.from( + new Uint8Array(await file.arrayBuffer()) + ); + } + let file_engine = { + files: file_contents, + }; + contents.files = file_engine; + + if (realId === null) { + return; + } + const message = serializeIpcMessage("user_event", { + name: name, + element: parseInt(realId), + data: contents, + bubbles, + }); + window.ipc.postMessage(message); + } + read_files(); + return; + } + }"#; + + interpreter.replace("/*POST_EVENT_SERIALIZATION*/", serialize_file_uploads) +}); + static MAIN_JS: &str = include_str!("./main.js"); /// This script that gets injected into your app connects this page to the websocket endpoint @@ -42,11 +86,12 @@ static MAIN_JS: &str = include_str!("./main.js"); /// Once the endpoint is connected, it will send the initial state of the app, and then start /// processing user events and returning edits to the liveview instance pub fn interpreter_glue(url: &str) -> String { + let js = &*INTERPRETER_JS; format!( r#" From d749fff11b06718215f8d1bb77b06799c7a23d1f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 14:29:35 -0500 Subject: [PATCH 465/895] fix double diologs on desktop renderer --- packages/desktop/src/lib.rs | 13 +++++++++---- packages/desktop/src/protocol.rs | 3 +-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 4d904e948..807ebf48e 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -273,16 +273,21 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) let event_name = &file_diolog.event; let event_bubbles = file_diolog.bubbles; let files = file_upload::get_file_event(&file_diolog); - let data = FormData { + let data = Rc::new(FormData { value: Default::default(), values: Default::default(), files: Some(Arc::new(NativeFileEngine::new(files))), - }; + }); let view = webviews.get_mut(&event.1).unwrap(); - view.dom - .handle_event(event_name, Rc::new(data), id, event_bubbles); + if event_name == "change&input" { + view.dom + .handle_event("input", data.clone(), id, event_bubbles); + view.dom.handle_event("change", data, id, event_bubbles); + } else { + view.dom.handle_event(event_name, data, id, event_bubbles); + } send_edits(view.dom.render_immediate(), &view.webview); } diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index f6725c428..e35d67bb1 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -27,8 +27,7 @@ fn module_loader(root_name: &str) -> String { const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); window.ipc.postMessage(message); }; - send("change"); - send("input"); + send("change&input"); } event.preventDefault(); } From 2f8d6fb49f9240b4a084d7ce381cba7a98998473 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 15:07:22 -0500 Subject: [PATCH 466/895] fix clippy --- examples/file_upload.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/file_upload.rs b/examples/file_upload.rs index c43e6e6ef..700c5392e 100644 --- a/examples/file_upload.rs +++ b/examples/file_upload.rs @@ -19,7 +19,7 @@ fn App(cx: Scope) -> Element { if let Some(file_engine) = &evt.files { let files = file_engine.files(); for file_name in &files { - if let Some(file) = file_engine.read_file_to_string(&file_name).await{ + if let Some(file) = file_engine.read_file_to_string(file_name).await{ files_uploaded.write().push(file); } } From 254947a1948239081b979fb740827b573f82e709 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 15:08:53 -0500 Subject: [PATCH 467/895] fix liveview tokio features --- packages/liveview/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index 5269927b0..2dbc09c71 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -18,7 +18,7 @@ futures-util = { version = "0.3.25", default-features = false, features = [ "sink", ] } futures-channel = { version = "0.3.25", features = ["sink"] } -tokio = { version = "1.22.0", features = ["time"] } +tokio = { version = "1.22.0", features = ["time", "macros"] } tokio-stream = { version = "0.1.11", features = ["net"] } tokio-util = { version = "0.7.4", features = ["rt"] } serde = { version = "1.0.151", features = ["derive"] } From 36a2c863bfe5ff62a9eb90dd8482f861200963af Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Apr 2023 15:16:02 -0500 Subject: [PATCH 468/895] fix dioxus-tui tests --- packages/dioxus-tui/Cargo.toml | 2 +- packages/dioxus-tui/tests/events.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/dioxus-tui/Cargo.toml b/packages/dioxus-tui/Cargo.toml index 43e568b0f..18388b12e 100644 --- a/packages/dioxus-tui/Cargo.toml +++ b/packages/dioxus-tui/Cargo.toml @@ -21,7 +21,7 @@ dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" } dioxus-hot-reload = { path = "../hot-reload", optional = true } rink = { path = "../rink" } -crossterm = "0.23.0" +crossterm = "0.26.0" tokio = { version = "1.15.0", features = ["full"] } futures = "0.3.19" taffy = "0.2.1" diff --git a/packages/dioxus-tui/tests/events.rs b/packages/dioxus-tui/tests/events.rs index c4be26e4a..671cfc349 100644 --- a/packages/dioxus-tui/tests/events.rs +++ b/packages/dioxus-tui/tests/events.rs @@ -47,10 +47,14 @@ fn key_down() { tui_ctx.inject_event(Event::Key(KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::NONE, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE, })); tui_ctx.inject_event(Event::Key(KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::NONE, + kind: crossterm::event::KeyEventKind::Press, + state: crossterm::event::KeyEventState::NONE, })); cx.render(rsx! { div { From cfe94950c62e27bdc8efc41573811386dda65ea7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Apr 2023 18:05:13 -0500 Subject: [PATCH 469/895] make files optional when deserializing form data --- packages/html/src/events/form.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index ec65ffe03..113c765c5 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -14,7 +14,11 @@ pub struct FormData { #[cfg_attr( feature = "serialize", - serde(skip_serializing, deserialize_with = "deserialize_file_engine") + serde( + default, + skip_serializing, + deserialize_with = "deserialize_file_engine" + ) )] pub files: Option>, } From c9044111908338c347b2b00bb48f579e5d9e1877 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 27 Apr 2023 05:27:07 -0700 Subject: [PATCH 470/895] Fix typo in event_handlers.md (#991) --- docs/guide/src/en/interactivity/event_handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/src/en/interactivity/event_handlers.md b/docs/guide/src/en/interactivity/event_handlers.md index 5e12ce259..bee0175e2 100644 --- a/docs/guide/src/en/interactivity/event_handlers.md +++ b/docs/guide/src/en/interactivity/event_handlers.md @@ -31,7 +31,7 @@ Some events will trigger first on the element the event originated at upward. Fo > For more information about event propigation see [the mdn docs on event bubling](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling) -If you want to prevent this behavior, you can call `stop_propogation()` on the event: +If you want to prevent this behavior, you can call `stop_propagation()` on the event: ```rust {{#include ../../../examples/event_nested.rs:rsx}} From c645e1c6aaa44829b38f273d97f5ae274a5671f5 Mon Sep 17 00:00:00 2001 From: Attilio <75045331+attilio-oliva@users.noreply.github.com> Date: Thu, 27 Apr 2023 18:26:04 +0200 Subject: [PATCH 471/895] Allow multiple prevent default for Web, Desktop and LiveView (#987) * Allow multiple prevent default in dioxus_web * Use SplitWhitespace for prevent default requests * Add multiple prevent default option to liveview and desktop * Update docs about prevent_default attribute * cargo clippy * update prevent default guide example --------- Co-authored-by: Evan Almloff --- docs/guide/examples/event_prevent_default.rs | 3 +-- .../src/en/interactivity/event_handlers.md | 2 +- packages/interpreter/src/interpreter.js | 18 +++++++++++------- packages/web/src/dom.rs | 12 ++++++++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/guide/examples/event_prevent_default.rs b/docs/guide/examples/event_prevent_default.rs index b109700bf..32443d017 100644 --- a/docs/guide/examples/event_prevent_default.rs +++ b/docs/guide/examples/event_prevent_default.rs @@ -10,8 +10,7 @@ fn App(cx: Scope) -> Element { // ANCHOR: prevent_default cx.render(rsx! { input { - prevent_default: "oninput", - prevent_default: "onclick", + prevent_default: "oninput onclick", } }) // ANCHOR_END: prevent_default diff --git a/docs/guide/src/en/interactivity/event_handlers.md b/docs/guide/src/en/interactivity/event_handlers.md index bee0175e2..317038923 100644 --- a/docs/guide/src/en/interactivity/event_handlers.md +++ b/docs/guide/src/en/interactivity/event_handlers.md @@ -41,7 +41,7 @@ If you want to prevent this behavior, you can call `stop_propagation()` on the e Some events have a default behavior. For keyboard events, this might be entering the typed character. For mouse events, this might be selecting some text. -In some instances, might want to avoid this default behavior. For this, you can add the `prevent_default` attribute with the name of the handler whose default behavior you want to stop. This attribute is special: you can attach it multiple times for multiple attributes: +In some instances, might want to avoid this default behavior. For this, you can add the `prevent_default` attribute with the name of the handler whose default behavior you want to stop. This attribute can be used for multiple handlers using their name separated by spaces: ```rust {{#include ../../../examples/event_prevent_default.rs:prevent_default}} diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index 9b93ec9e3..d7b74a63e 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -352,7 +352,7 @@ class Interpreter { let target = event.target; if (target != null) { let realId = target.getAttribute(`data-dioxus-id`); - let shouldPreventDefault = target.getAttribute( + let preventDefaultRequests = target.getAttribute( `dioxus-prevent-default` ); @@ -361,10 +361,14 @@ class Interpreter { let a_element = target.closest("a"); if (a_element != null) { event.preventDefault(); - if ( - shouldPreventDefault !== `onclick` && - a_element.getAttribute(`dioxus-prevent-default`) !== `onclick` - ) { + + let elementShouldPreventDefault = + preventDefaultRequests.includes(`onclick`); + let linkShouldPreventDefault = a_element + .getAttribute(`dioxus-prevent-default`) + .includes(`onclick`); + + if (!elementShouldPreventDefault && !linkShouldPreventDefault) { const href = a_element.getAttribute("href"); if (href !== "" && href !== null && href !== undefined) { window.ipc.postMessage( @@ -390,13 +394,13 @@ class Interpreter { realId = target.getAttribute(`data-dioxus-id`); } - shouldPreventDefault = target.getAttribute( + preventDefaultRequests = target.getAttribute( `dioxus-prevent-default` ); let contents = serialize_event(event); - if (shouldPreventDefault === `on${event.type}`) { + if (preventDefaultRequests.includes(`on${event.type}`)) { event.preventDefault(); } diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index e1e3b6365..20119dd25 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -55,13 +55,17 @@ impl WebsysDom { let element = walk_event_for_id(event); let bubbles = dioxus_html::event_bubbles(name.as_str()); if let Some((element, target)) = element { - if target + if let Some(prevent_requests) = target .get_attribute("dioxus-prevent-default") .as_deref() - .map(|f| f.trim_start_matches("on")) - == Some(&name) + .map(|f| f.split_whitespace()) { - event.prevent_default(); + if prevent_requests + .map(|f| f.trim_start_matches("on")) + .any(|f| f == name) + { + event.prevent_default(); + } } let data = virtual_event_from_websys_event(event.clone(), target); From f044bb212889eb2539286ed28c9f37f4c4f3d03c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 27 Apr 2023 15:19:10 -0500 Subject: [PATCH 472/895] fix onclick event --- packages/desktop/src/file_upload.rs | 5 +- packages/desktop/src/protocol.rs | 16 +-- packages/interpreter/src/interpreter.js | 129 ++++-------------------- 3 files changed, 32 insertions(+), 118 deletions(-) diff --git a/packages/desktop/src/file_upload.rs b/packages/desktop/src/file_upload.rs index ae4a81cc2..1b24ffc55 100644 --- a/packages/desktop/src/file_upload.rs +++ b/packages/desktop/src/file_upload.rs @@ -4,7 +4,8 @@ use serde::Deserialize; #[derive(Debug, Deserialize)] pub(crate) struct FileDiologRequest { - accept: String, + #[serde(default)] + accept: Option, multiple: bool, pub event: String, pub target: usize, @@ -16,6 +17,8 @@ pub(crate) fn get_file_event(request: &FileDiologRequest) -> Vec { let filters: Vec<_> = request .accept + .as_deref() + .unwrap_or_default() .split(',') .filter_map(|s| Filters::from_str(s).ok()) .collect(); diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index e35d67bb1..2e407b258 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -15,12 +15,12 @@ fn module_loader(root_name: &str) -> String { let inputs = document.querySelectorAll("input"); for (let input of inputs) { if (!input.getAttribute("data-dioxus-file-listener")) { - input.setAttribute("data-dioxus-file-listener", true); - input.addEventListener("click", (event) => { - let target = event.target; - // prevent file inputs from opening the file dialog on click - const type = target.getAttribute("type"); - if (type === "file") { + // prevent file inputs from opening the file dialog on click + const type = input.getAttribute("type"); + if (type === "file") { + input.setAttribute("data-dioxus-file-listener", true); + input.addEventListener("click", (event) => { + let target = event.target; let target_id = find_real_id(target); if (target_id !== null) { const send = (event_name) => { @@ -30,8 +30,8 @@ fn module_loader(root_name: &str) -> String { send("change&input"); } event.preventDefault(); - } - }); + }); + } } }"#, ); diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index d7b74a63e..e3c8579a4 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -346,106 +346,9 @@ class Interpreter { case "NewEventListener": let bubbles = event_bubbles(edit.name); - // this handler is only provided on desktop implementations since this - // method is not used by the web implementation - let handler = (event) => { - let target = event.target; - if (target != null) { - let realId = target.getAttribute(`data-dioxus-id`); - let preventDefaultRequests = target.getAttribute( - `dioxus-prevent-default` - ); - - if (event.type === "click") { - // todo call prevent default if it's the right type of event - let a_element = target.closest("a"); - if (a_element != null) { - event.preventDefault(); - - let elementShouldPreventDefault = - preventDefaultRequests.includes(`onclick`); - let linkShouldPreventDefault = a_element - .getAttribute(`dioxus-prevent-default`) - .includes(`onclick`); - - if (!elementShouldPreventDefault && !linkShouldPreventDefault) { - const href = a_element.getAttribute("href"); - if (href !== "" && href !== null && href !== undefined) { - window.ipc.postMessage( - serializeIpcMessage("browser_open", { href }) - ); - } - } - } - - // also prevent buttons from submitting - if (target.tagName === "BUTTON" && event.type == "submit") { - event.preventDefault(); - } - } - // walk the tree to find the real element - while (realId == null) { - // we've reached the root we don't want to send an event - if (target.parentElement === null) { - return; - } - - target = target.parentElement; - realId = target.getAttribute(`data-dioxus-id`); - } - - preventDefaultRequests = target.getAttribute( - `dioxus-prevent-default` - ); - - let contents = serialize_event(event); - - if (preventDefaultRequests.includes(`on${event.type}`)) { - event.preventDefault(); - } - - if (event.type === "submit") { - event.preventDefault(); - } - - if ( - target.tagName === "FORM" && - (event.type === "submit" || event.type === "input") - ) { - for (let x = 0; x < target.elements.length; x++) { - let element = target.elements[x]; - let name = element.getAttribute("name"); - if (name != null) { - if (element.getAttribute("type") === "checkbox") { - // @ts-ignore - contents.values[name] = element.checked ? "true" : "false"; - } else if (element.getAttribute("type") === "radio") { - if (element.checked) { - contents.values[name] = element.value; - } - } else { - // @ts-ignore - contents.values[name] = - element.value ?? element.textContent; - } - } - } - } - - if (realId === null) { - return; - } - window.ipc.postMessage( - serializeIpcMessage("user_event", { - name: edit.name, - element: parseInt(realId), - data: contents, - bubbles, - }) - ); - } - }; - this.NewEventListener(edit.name, edit.id, bubbles, handler); + this.NewEventListener(edit.name, edit.id, bubbles, (event) => { + handler(event, edit.name, bubbles); + }); break; } } @@ -456,17 +359,24 @@ class Interpreter { function handler(event, name, bubbles) { let target = event.target; if (target != null) { - let shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`); + let preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`); if (event.type === "click") { - // Prevent redirects from links + // todo call prevent default if it's the right type of event let a_element = target.closest("a"); if (a_element != null) { event.preventDefault(); - if ( - shouldPreventDefault !== `onclick` && - a_element.getAttribute(`dioxus-prevent-default`) !== `onclick` - ) { + + let elementShouldPreventDefault = + preventDefaultRequests && preventDefaultRequests.includes(`onclick`); + let aElementShouldPreventDefault = a_element.getAttribute( + `dioxus-prevent-default` + ); + let linkShouldPreventDefault = + aElementShouldPreventDefault && + aElementShouldPreventDefault.includes(`onclick`); + + if (!elementShouldPreventDefault && !linkShouldPreventDefault) { const href = a_element.getAttribute("href"); if (href !== "" && href !== null && href !== undefined) { window.ipc.postMessage( @@ -484,9 +394,10 @@ function handler(event, name, bubbles) { const realId = find_real_id(target); - shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`); - - if (shouldPreventDefault === `on${event.type}`) { + if ( + preventDefaultRequests && + preventDefaultRequests.includes(`on${event.type}`) + ) { event.preventDefault(); } From f381e56ab396542bb4955c9afe3875dc67707b6b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 27 Apr 2023 16:38:09 -0500 Subject: [PATCH 473/895] test scafolding --- packages/desktop/Cargo.toml | 6 ++++++ packages/desktop/headless_tests/main.rs | 28 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 packages/desktop/headless_tests/main.rs diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 8b41019e1..af5f3e68f 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -57,4 +57,10 @@ hot-reload = ["dioxus-hot-reload"] [dev-dependencies] dioxus-core-macro = { path = "../core-macro" } dioxus-hooks = { path = "../hooks" } +dioxus = { path = "../dioxus" } # image = "0.24.0" # enable this when generating a new desktop image + +[[test]] +name = "headless_tests" +path = "headless_tests/main.rs" +harness = false \ No newline at end of file diff --git a/packages/desktop/headless_tests/main.rs b/packages/desktop/headless_tests/main.rs new file mode 100644 index 000000000..e07cb08c3 --- /dev/null +++ b/packages/desktop/headless_tests/main.rs @@ -0,0 +1,28 @@ +// Check that all events are being forwarded to the mock. +//! This example roughly shows how events are serialized into Rust from JavaScript. +//! +//! There is some conversion happening when input types are checkbox/radio/select/textarea etc. + +use dioxus::prelude::*; + +mod events; + +fn main() { + events::test_events(); +} + +pub(crate) fn check_app_exits(app: Component) { + // This is a deadman's switch to ensure that the app exits + let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)); + let should_panic_clone = should_panic.clone(); + std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_secs(100)); + if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) { + panic!("App did not exit successfully") + } + }); + + dioxus_desktop::launch(app); + + should_panic.store(false, std::sync::atomic::Ordering::SeqCst); +} From 01d673e6544c26395d8d719c19a507af2c95f611 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 27 Apr 2023 18:00:43 -0500 Subject: [PATCH 474/895] create event tests --- packages/desktop/Cargo.toml | 2 +- packages/desktop/headless_tests/events.rs | 290 ++++++++++++++++++++++ packages/desktop/headless_tests/main.rs | 4 +- 3 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 packages/desktop/headless_tests/events.rs diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index af5f3e68f..e8812df5a 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -58,7 +58,7 @@ hot-reload = ["dioxus-hot-reload"] dioxus-core-macro = { path = "../core-macro" } dioxus-hooks = { path = "../hooks" } dioxus = { path = "../dioxus" } -# image = "0.24.0" # enable this when generating a new desktop image +exitcode = "1.1.2" [[test]] name = "headless_tests" diff --git a/packages/desktop/headless_tests/events.rs b/packages/desktop/headless_tests/events.rs new file mode 100644 index 000000000..34e29f024 --- /dev/null +++ b/packages/desktop/headless_tests/events.rs @@ -0,0 +1,290 @@ +use crate::check_app_exits; +use dioxus::prelude::*; +use dioxus_desktop::DesktopContext; +use dioxus::html::geometry::euclid::Vector3D; + +pub fn test_events() { + check_app_exits(app); +} + +fn mock_event(cx: &ScopeState, id: &'static str, value: &'static str) { + use_effect(cx, (), |_| { + let desktop_context: DesktopContext = cx.consume_context().unwrap(); + async move { + desktop_context.eval(&format!( + r#"let element = document.getElementById('{}'); + // Dispatch a synthetic event + const event = {}; + element.dispatchEvent(event); + "#, + id, value + )); + } + }); +} + +#[allow(deprecated)] +fn app(cx: Scope) -> Element { + let desktop_context: DesktopContext = cx.consume_context().unwrap(); + let recieved_events = use_state(cx, || 0); + + // button + mock_event( + &cx, + "button", + r#"new MouseEvent("click", { + view: window, + bubbles: true, + cancelable: true, + button: 0, + })"#, + ); + // mouse_move_div + mock_event( + &cx, + "mouse_move_div", + r#"new MouseEvent("mousemove", { + view: window, + bubbles: true, + cancelable: true, + buttons: 2, + })"#, + ); + // mouse_click_div + mock_event( + &cx, + "mouse_click_div", + r#"new MouseEvent("click", { + view: window, + bubbles: true, + cancelable: true, + buttons: 2, + button: 2, + })"# + ); + // mouse_dblclick_div + mock_event( + &cx, + "mouse_dblclick_div", + r#"new MouseEvent("dblclick", { + view: window, + bubbles: true, + cancelable: true, + buttons: 1|2, + button: 2, + })"#, + ); + // mouse_down_div + mock_event( + &cx, + "mouse_down_div", + r#"new MouseEvent("mousedown", { + view: window, + bubbles: true, + cancelable: true, + buttons: 2, + button: 2, + })"#, + ); + // mouse_up_div + mock_event( + &cx, + "mouse_up_div", + r#"new MouseEvent("mouseup", { + view: window, + bubbles: true, + cancelable: true, + buttons: 0, + button: 0, + })"#, + ); + // wheel_div + mock_event( + &cx, + "wheel_div", + r#"new WheelEvent("wheel", { + deltaX: 1.0, + deltaY: 2.0, + deltaZ: 3.0, + })"#, + ); + // key_down_div + mock_event( + &cx, + "key_down_div", + r#"new KeyboardEvent("keydown", { + key: "a", + code: "KeyA", + location: 0, + repeat: true, + })"#, + ); + // key_up_div + mock_event( + &cx, + "key_up_div", + r#"new KeyboardEvent("keyup", { + key: "a", + code: "KeyA", + location: 0, + repeat: false, + })"#, + ); + // key_press_div + mock_event( + &cx, + "key_press_div", + r#"new KeyboardEvent("keypress", { + key: "a", + code: "KeyA", + location: 0, + repeat: false, + })"#, + ); + // focus_in_div + mock_event( + &cx, + "focus_in_div", + r#"new FocusEvent("focusin")"#, + ); + // focus_out_div + mock_event( + &cx, + "focus_out_div", + r#"new FocusEvent("focusout")"#, + ); + + + if **recieved_events == 12 { + desktop_context.close(); + } + + cx.render(rsx! { + div { + button { + id: "button", + onclick: 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)); + 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)); + 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)); + 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)); + recieved_events.modify(|x| *x + 1) + } + } + 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)); + recieved_events.modify(|x| *x + 1) + } + } + div{ + id: "wheel_div", + onwheel: move |event| { + println!("{:?}", event.data); + 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) + } + } + div{ + id: "key_down_div", + onkeydown: move |event| { + println!("{:?}", event.data); + assert!(event.data.modifiers().is_empty()); + assert_eq!(event.data.key().to_string(), "a"); + 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) + } + } + div{ + id: "key_up_div", + onkeyup: move |event| { + println!("{:?}", event.data); + assert!(event.data.modifiers().is_empty()); + assert_eq!(event.data.key().to_string(), "a"); + 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) + } + } + div{ + id: "key_press_div", + onkeypress: move |event| { + println!("{:?}", event.data); + assert!(event.data.modifiers().is_empty()); + assert_eq!(event.data.key().to_string(), "a"); + 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) + } + } + div{ + id: "focus_in_div", + onfocusin: move |event| { + println!("{:?}", event.data); + recieved_events.modify(|x| *x + 1) + } + } + div{ + id: "focus_out_div", + onfocusout: move |event| { + println!("{:?}", event.data); + recieved_events.modify(|x| *x + 1) + } + } + } + }) +} diff --git a/packages/desktop/headless_tests/main.rs b/packages/desktop/headless_tests/main.rs index e07cb08c3..65b6c80a3 100644 --- a/packages/desktop/headless_tests/main.rs +++ b/packages/desktop/headless_tests/main.rs @@ -16,9 +16,9 @@ pub(crate) fn check_app_exits(app: Component) { let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)); let should_panic_clone = should_panic.clone(); std::thread::spawn(move || { - std::thread::sleep(std::time::Duration::from_secs(100)); + std::thread::sleep(std::time::Duration::from_secs(10)); if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) { - panic!("App did not exit successfully") + std::process::exit(exitcode::SOFTWARE); } }); From 70687748d3577449d101e41a13a033c6cc76aa24 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 27 Apr 2023 18:36:28 -0500 Subject: [PATCH 475/895] fix events test --- packages/desktop/headless_tests/events.rs | 55 ++++++++++++++++++++--- packages/desktop/headless_tests/main.rs | 2 +- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/packages/desktop/headless_tests/events.rs b/packages/desktop/headless_tests/events.rs index 34e29f024..60962c868 100644 --- a/packages/desktop/headless_tests/events.rs +++ b/packages/desktop/headless_tests/events.rs @@ -11,10 +11,12 @@ fn mock_event(cx: &ScopeState, id: &'static str, value: &'static str) { use_effect(cx, (), |_| { let desktop_context: DesktopContext = cx.consume_context().unwrap(); async move { + tokio::time::sleep(std::time::Duration::from_millis(100)).await; desktop_context.eval(&format!( r#"let element = document.getElementById('{}'); // Dispatch a synthetic event const event = {}; + console.log(element, event); element.dispatchEvent(event); "#, id, value @@ -103,9 +105,12 @@ fn app(cx: Scope) -> Element { &cx, "wheel_div", r#"new WheelEvent("wheel", { + view: window, deltaX: 1.0, deltaY: 2.0, deltaZ: 3.0, + deltaMode: 0x00, + bubbles: true, })"#, ); // key_down_div @@ -117,6 +122,17 @@ fn app(cx: Scope) -> Element { code: "KeyA", location: 0, repeat: true, + keyCode: 65, + charCode: 97, + char: "a", + charCode: 0, + altKey: false, + ctrlKey: false, + metaKey: false, + shiftKey: false, + isComposing: false, + which: 65, + bubbles: true, })"#, ); // key_up_div @@ -128,6 +144,17 @@ fn app(cx: Scope) -> Element { code: "KeyA", location: 0, repeat: false, + keyCode: 65, + charCode: 97, + char: "a", + charCode: 0, + altKey: false, + ctrlKey: false, + metaKey: false, + shiftKey: false, + isComposing: false, + which: 65, + bubbles: true, })"#, ); // key_press_div @@ -139,19 +166,30 @@ fn app(cx: Scope) -> Element { code: "KeyA", location: 0, repeat: false, + keyCode: 65, + charCode: 97, + char: "a", + charCode: 0, + altKey: false, + ctrlKey: false, + metaKey: false, + shiftKey: false, + isComposing: false, + which: 65, + bubbles: true, })"#, ); // focus_in_div mock_event( &cx, "focus_in_div", - r#"new FocusEvent("focusin")"#, + r#"new FocusEvent("focusin", {bubbles: true})"#, ); // focus_out_div mock_event( &cx, "focus_out_div", - r#"new FocusEvent("focusout")"#, + r#"new FocusEvent("focusout",{bubbles: true})"#, ); @@ -223,6 +261,9 @@ fn app(cx: Scope) -> Element { } 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{ @@ -232,7 +273,7 @@ fn app(cx: Scope) -> Element { recieved_events.modify(|x| *x + 1) } } - div{ + input{ id: "key_down_div", onkeydown: move |event| { println!("{:?}", event.data); @@ -245,7 +286,7 @@ fn app(cx: Scope) -> Element { recieved_events.modify(|x| *x + 1) } } - div{ + input{ id: "key_up_div", onkeyup: move |event| { println!("{:?}", event.data); @@ -258,7 +299,7 @@ fn app(cx: Scope) -> Element { recieved_events.modify(|x| *x + 1) } } - div{ + input{ id: "key_press_div", onkeypress: move |event| { println!("{:?}", event.data); @@ -271,14 +312,14 @@ fn app(cx: Scope) -> Element { recieved_events.modify(|x| *x + 1) } } - div{ + input{ id: "focus_in_div", onfocusin: move |event| { println!("{:?}", event.data); recieved_events.modify(|x| *x + 1) } } - div{ + input{ id: "focus_out_div", onfocusout: move |event| { println!("{:?}", event.data); diff --git a/packages/desktop/headless_tests/main.rs b/packages/desktop/headless_tests/main.rs index 65b6c80a3..a9d9ec61c 100644 --- a/packages/desktop/headless_tests/main.rs +++ b/packages/desktop/headless_tests/main.rs @@ -16,7 +16,7 @@ pub(crate) fn check_app_exits(app: Component) { let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)); let should_panic_clone = should_panic.clone(); std::thread::spawn(move || { - std::thread::sleep(std::time::Duration::from_secs(10)); + std::thread::sleep(std::time::Duration::from_secs(100)); if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) { std::process::exit(exitcode::SOFTWARE); } From 0726a7b08f5e499869c114e37aae973d029d6ad3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 27 Apr 2023 20:25:16 -0500 Subject: [PATCH 476/895] update server functions commit --- packages/server/Cargo.toml | 2 +- packages/server/server-macro/Cargo.toml | 2 +- packages/server/server-macro/src/lib.rs | 5 +- packages/server/src/adapters/axum_adapter.rs | 39 +++++++---- packages/server/src/adapters/salvo_adapter.rs | 44 ++++++++----- packages/server/src/adapters/warp_adapter.rs | 66 ++++++++++++++----- packages/server/src/lib.rs | 2 +- packages/server/src/server_fn.rs | 36 ++++++++-- 8 files changed, 138 insertions(+), 58 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 18633e97a..d182aa415 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"] [dependencies] # server functions -server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "a9e6590b5e7f1c0b01da7db7b86719cb18a4aaa1", features = ["stable"] } +server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", features = ["stable"] } dioxus_server_macro = { path = "server-macro" } # warp diff --git a/packages/server/server-macro/Cargo.toml b/packages/server/server-macro/Cargo.toml index 45b0ec3c6..286481bdd 100644 --- a/packages/server/server-macro/Cargo.toml +++ b/packages/server/server-macro/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] quote = "1.0.26" -server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "a9e6590b5e7f1c0b01da7db7b86719cb18a4aaa1", features = ["stable"] } +server_fn_macro = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", features = ["stable"] } syn = { version = "1", features = ["full"] } [lib] diff --git a/packages/server/server-macro/src/lib.rs b/packages/server/server-macro/src/lib.rs index 14fc0ac77..b3f890f6a 100644 --- a/packages/server/server-macro/src/lib.rs +++ b/packages/server/server-macro/src/lib.rs @@ -14,9 +14,10 @@ use server_fn_macro::*; /// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered /// (e.g., `"/api"`). Defaults to `"/"`. /// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for -/// serialization) or `"Url"` (specifying that it should be use a URL-encoded form-data string). +/// serialization), `"Url"` (specifying that it should be use a URL-encoded form-data string). /// Defaults to `"Url"`. If you want to use this server function to power a `` that will -/// work without WebAssembly, the encoding must be `"Url"`. +/// work without WebAssembly, the encoding must be `"Url"`. If you want to use this server function +/// using Get instead of Post methods, the encoding must be `"GetCbor"` or `"GetJson"`. /// /// The server function itself can take any number of arguments, each of which should be serializable /// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus-server/latest/dixous_server/prelude/struct.DioxusServerContext.html), diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index f4bdd8a96..2d16e9491 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -55,10 +55,9 @@ //! } //! ``` -use std::{error::Error, sync::Arc}; - use axum::{ body::{self, Body, BoxBody, Full}, + extract::RawQuery, extract::{State, WebSocketUpgrade}, handler::Handler, http::{HeaderMap, Request, Response, StatusCode}, @@ -66,14 +65,13 @@ use axum::{ routing::{get, post}, Router, }; -use server_fn::{Payload, ServerFunctionRegistry}; +use server_fn::{Encoding, Payload, ServerFunctionRegistry}; +use std::error::Error; use tokio::task::spawn_blocking; use crate::{ - render::SSRState, - serve_config::ServeConfig, - server_context::DioxusServerContext, - server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, + prelude::*, render::SSRState, serve_config::ServeConfig, server_context::DioxusServerContext, + server_fn::DioxusServerFnRegistry, }; /// A extension trait with utilities for integrating Dioxus with your Axum router. @@ -106,7 +104,7 @@ pub trait DioxusRouterExt { fn register_server_fns_with_handler( self, server_fn_route: &'static str, - handler: impl Fn(Arc) -> H, + handler: impl Fn(ServerFunction) -> H, ) -> Self where H: Handler, @@ -200,7 +198,7 @@ where fn register_server_fns_with_handler( self, server_fn_route: &'static str, - mut handler: impl FnMut(Arc) -> H, + mut handler: impl FnMut(ServerFunction) -> H, ) -> Self where H: Handler, @@ -211,15 +209,22 @@ where for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); let full_route = format!("{server_fn_route}/{server_fn_path}"); - router = router.route(&full_route, post(handler(func))); + match func.encoding { + Encoding::Url | Encoding::Cbor => { + router = router.route(&full_route, post(handler(func))); + } + Encoding::GetJSON | Encoding::GetCBOR => { + router = router.route(&full_route, get(handler(func))); + } + } } router } fn register_server_fns(self, server_fn_route: &'static str) -> Self { self.register_server_fns_with_handler(server_fn_route, |func| { - move |headers: HeaderMap, body: Request| async move { - server_fn_handler((), func.clone(), headers, body).await + move |headers: HeaderMap, RawQuery(query): RawQuery, body: Request| async move { + server_fn_handler((), func.clone(), headers, query, body).await } }) } @@ -299,8 +304,9 @@ async fn render_handler( /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub async fn server_fn_handler( server_context: impl Into, - function: Arc, + function: ServerFunction, headers: HeaderMap, + query: Option, req: Request, ) -> impl IntoResponse { let server_context = server_context.into(); @@ -317,7 +323,12 @@ pub async fn server_fn_handler( tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") .block_on(async { - let resp = match function(server_context, &body).await { + let query = &query.unwrap_or_default().into(); + let data = match &function.encoding { + Encoding::Url | Encoding::Cbor => &body, + Encoding::GetJSON | Encoding::GetCBOR => query, + }; + let resp = match (function.trait_obj)(server_context, &data).await { Ok(serialized) => { // if this is Accept: application/json then send a serialized JSON response let accept_header = diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index ffe72bef5..402a0b0a0 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -50,7 +50,7 @@ //! } //! ``` -use std::{error::Error, sync::Arc}; +use std::error::Error; use hyper::{http::HeaderValue, StatusCode}; use salvo::{ @@ -58,14 +58,11 @@ use salvo::{ serve_static::{StaticDir, StaticFile}, Depot, FlowCtrl, Handler, Request, Response, Router, }; -use server_fn::{Payload, ServerFunctionRegistry}; +use server_fn::{Encoding, Payload, ServerFunctionRegistry}; use tokio::task::spawn_blocking; use crate::{ - prelude::DioxusServerContext, - render::SSRState, - serve_config::ServeConfig, - server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, + prelude::*, render::SSRState, serve_config::ServeConfig, server_fn::DioxusServerFnRegistry, }; /// A extension trait with utilities for integrating Dioxus with your Salvo router. @@ -79,7 +76,7 @@ pub trait DioxusRouterExt { /// use dioxus_server::prelude::*; /// /// struct ServerFunctionHandler { - /// server_fn: Arc, + /// server_fn: ServerFunction, /// } /// /// #[handler] @@ -112,7 +109,7 @@ pub trait DioxusRouterExt { fn register_server_fns_with_handler( self, server_fn_route: &'static str, - handler: impl Fn(Arc) -> H, + handler: impl Fn(ServerFunction) -> H, ) -> Self where H: Handler + 'static; @@ -187,7 +184,7 @@ impl DioxusRouterExt for Router { fn register_server_fns_with_handler( self, server_fn_route: &'static str, - mut handler: impl FnMut(Arc) -> H, + mut handler: impl FnMut(ServerFunction) -> H, ) -> Self where H: Handler + 'static, @@ -196,7 +193,14 @@ impl DioxusRouterExt for Router { for server_fn_path in DioxusServerFnRegistry::paths_registered() { let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); let full_route = format!("{server_fn_route}/{server_fn_path}"); - router = router.push(Router::with_path(&full_route).post(handler(func))); + match func.encoding { + Encoding::Url | Encoding::Cbor => { + router = router.push(Router::with_path(&full_route).post(handler(func))); + } + Encoding::GetJSON | Encoding::GetCBOR => { + router = router.push(Router::with_path(&full_route).get(handler(func))); + } + } } router } @@ -288,15 +292,12 @@ impl Handler for SSRHandler

{ /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub struct ServerFnHandler { server_context: DioxusServerContext, - function: Arc, + function: ServerFunction, } impl ServerFnHandler { /// Create a new server function handler with the given server context and server function. - pub fn new( - server_context: impl Into, - function: Arc, - ) -> Self { + pub fn new(server_context: impl Into, function: ServerFunction) -> Self { let server_context = server_context.into(); Self { server_context, @@ -324,12 +325,23 @@ impl ServerFnHandler { let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); let function = function.clone(); let server_context = server_context.clone(); + let query = req + .uri() + .query() + .unwrap_or_default() + .as_bytes() + .to_vec() + .into(); spawn_blocking({ move || { tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") .block_on(async move { - let resp = function(server_context, &body).await; + let data = match &function.encoding { + Encoding::Url | Encoding::Cbor => &body, + Encoding::GetJSON | Encoding::GetCBOR => &query, + }; + let resp = (function.trait_obj)(server_context, data).await; resp_tx.send(resp).unwrap(); }) diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 5041e294d..db88ac2b4 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -47,9 +47,12 @@ //! //! ``` -use std::{error::Error, sync::Arc}; +use crate::{ + prelude::*, render::SSRState, serve_config::ServeConfig, server_fn::DioxusServerFnRegistry, +}; -use server_fn::{Payload, ServerFunctionRegistry}; +use server_fn::{Encoding, Payload, ServerFunctionRegistry}; +use std::error::Error; use tokio::task::spawn_blocking; use warp::{ filters::BoxedFilter, @@ -58,13 +61,6 @@ use warp::{ path, Filter, Reply, }; -use crate::{ - prelude::DioxusServerContext, - render::SSRState, - serve_config::ServeConfig, - server_fn::{DioxusServerFnRegistry, ServerFnTraitObj}, -}; - /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. /// /// # Example @@ -94,7 +90,7 @@ pub fn register_server_fns_with_handler( mut handler: H, ) -> BoxedFilter<(R,)> where - H: FnMut(String, Arc) -> F, + H: FnMut(String, ServerFunction) -> F, F: Filter + Send + Sync + 'static, F::Extract: Send, R: Reply + 'static, @@ -129,16 +125,48 @@ where /// ``` pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { register_server_fns_with_handler(server_fn_route, |full_route, func| { - path(full_route) - .and(warp::post()) + let func2 = func.clone(); + let func3 = func.clone(); + path(full_route.clone()) + .and(warp::filters::method::get()) .and(warp::header::headers_cloned()) + .and(warp::filters::query::raw()) .and(warp::body::bytes()) - .and_then(move |headers: HeaderMap, body| { + .and_then(move |headers, query, body| { let func = func.clone(); async move { - server_fn_handler(DioxusServerContext::default(), func, headers, body).await + server_fn_handler( + DioxusServerContext::default(), + func, + headers, + Some(query), + body, + ) + .await } }) + .or(path(full_route.clone()) + .and(warp::filters::method::get()) + .and(warp::header::headers_cloned()) + .and(warp::body::bytes()) + .and_then(move |headers, body| { + let func = func2.clone(); + async move { + server_fn_handler(DioxusServerContext::default(), func, headers, None, body) + .await + } + })) + .or(path(full_route) + .and(warp::filters::method::post()) + .and(warp::header::headers_cloned()) + .and(warp::body::bytes()) + .and_then(move |headers, body| { + let func = func3.clone(); + async move { + server_fn_handler(DioxusServerContext::default(), func, headers, None, body) + .await + } + })) }) } @@ -198,8 +226,9 @@ impl warp::reject::Reject for RecieveFailed {} /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub async fn server_fn_handler( server_context: impl Into, - function: Arc, + function: ServerFunction, headers: HeaderMap, + query: Option, body: Bytes, ) -> Result, warp::Rejection> { let server_context = server_context.into(); @@ -210,7 +239,12 @@ pub async fn server_fn_handler( tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") .block_on(async { - let resp = match function(server_context, &body).await { + let query = &query.unwrap_or_default().into(); + let data = match &function.encoding { + Encoding::Url | Encoding::Cbor => &body, + Encoding::GetJSON | Encoding::GetCBOR => query, + }; + let resp = match (function.trait_obj)(server_context, &data).await { Ok(serialized) => { // if this is Accept: application/json then send a serialized JSON response let accept_header = diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index df2735cf4..525b636b3 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -30,7 +30,7 @@ pub mod prelude { pub use crate::server_context::DioxusServerContext; pub use crate::server_fn::ServerFn; #[cfg(feature = "ssr")] - pub use crate::server_fn::ServerFnTraitObj; + pub use crate::server_fn::{ServerFnTraitObj, ServerFunction}; pub use dioxus_server_macro::*; pub use server_fn::{self, ServerFn as _, ServerFnError}; } diff --git a/packages/server/src/server_fn.rs b/packages/server/src/server_fn.rs index 643f25c9f..da7311263 100644 --- a/packages/server/src/server_fn.rs +++ b/packages/server/src/server_fn.rs @@ -4,14 +4,14 @@ use crate::server_context::DioxusServerContext; /// A trait object for a function that be called on serializable arguments and returns a serializable result. pub type ServerFnTraitObj = server_fn::ServerFnTraitObj; +#[cfg(any(feature = "ssr", doc))] +/// A server function that can be called on serializable arguments and returns a serializable result. +pub type ServerFunction = server_fn::ServerFunction; + #[cfg(any(feature = "ssr", doc))] #[allow(clippy::type_complexity)] static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< - std::sync::Arc< - std::sync::RwLock< - std::collections::HashMap<&'static str, std::sync::Arc>, - >, - >, + std::sync::Arc>>, > = once_cell::sync::Lazy::new(Default::default); #[cfg(any(feature = "ssr", doc))] @@ -25,12 +25,19 @@ impl server_fn::ServerFunctionRegistry for DioxusServerFnRe fn register( url: &'static str, server_function: std::sync::Arc, + encoding: server_fn::Encoding, ) -> Result<(), Self::Error> { // store it in the hashmap let mut write = REGISTERED_SERVER_FUNCTIONS .write() .map_err(|e| ServerRegistrationFnError::Poisoned(e.to_string()))?; - let prev = write.insert(url, server_function); + let prev = write.insert( + url, + ServerFunction { + trait_obj: server_function, + encoding, + }, + ); // if there was already a server function with this key, // return Err @@ -47,13 +54,28 @@ impl server_fn::ServerFunctionRegistry for DioxusServerFnRe } /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL. - fn get(url: &str) -> Option> { + fn get(url: &str) -> Option { REGISTERED_SERVER_FUNCTIONS .read() .ok() .and_then(|fns| fns.get(url).cloned()) } + /// Returns the server function registered at the given URL, or `None` if no function is registered at that URL. + fn get_trait_obj(url: &str) -> Option> { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .and_then(|fns| fns.get(url).map(|f| f.trait_obj.clone())) + } + + fn get_encoding(url: &str) -> Option { + REGISTERED_SERVER_FUNCTIONS + .read() + .ok() + .and_then(|fns| fns.get(url).map(|f| f.encoding.clone())) + } + /// Returns a list of all registered server functions. fn paths_registered() -> Vec<&'static str> { REGISTERED_SERVER_FUNCTIONS From 03a282466026b0bb68b9e6581c3e6ccec9fd0ac8 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 28 Apr 2023 17:59:01 -0500 Subject: [PATCH 477/895] allow passing root prop data from the server to the client --- packages/server/Cargo.toml | 5 ++ .../examples/axum-hello-world/src/main.rs | 21 ++++- .../examples/salvo-hello-world/src/main.rs | 22 +++-- .../examples/warp-hello-world/src/main.rs | 21 ++++- packages/server/src/adapters/axum_adapter.rs | 6 +- packages/server/src/adapters/salvo_adapter.rs | 6 +- packages/server/src/adapters/warp_adapter.rs | 2 +- packages/server/src/lib.rs | 4 + .../src/props_html/deserialize_props.rs | 37 ++++++++ packages/server/src/props_html/mod.rs | 85 +++++++++++++++++++ .../server/src/props_html/serialize_props.rs | 37 ++++++++ packages/server/src/render.rs | 5 +- 12 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 packages/server/src/props_html/deserialize_props.rs create mode 100644 packages/server/src/props_html/mod.rs create mode 100644 packages/server/src/props_html/serialize_props.rs diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index d182aa415..2e20cdc81 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -44,10 +44,15 @@ anymap = "0.12.1" serde_json = { version = "1.0.95", optional = true } tokio-stream = { version = "0.1.12", features = ["sync"], optional = true } futures-util = { version = "0.3.28", optional = true } +postcard = { version = "1.0.4", features = ["use-std"] } +yazi = "0.1.5" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] dioxus-hot-reload = { path = "../hot-reload" } +[target.'cfg(target_arch = "wasm32")'.dependencies] +web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "HtmlDocument", "Storage", "console"] } + [features] default = ["hot-reload"] hot-reload = ["serde_json", "tokio-stream", "futures-util"] diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index 899247af5..b5553f7a2 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -8,10 +8,15 @@ #![allow(non_snake_case)] use dioxus::prelude::*; use dioxus_server::prelude::*; +use serde::{Deserialize, Serialize}; fn main() { #[cfg(feature = "web")] - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + dioxus_web::launch_with_props( + app, + get_props_from_document().unwrap_or_default(), + dioxus_web::Config::new().hydrate(true), + ); #[cfg(feature = "ssr")] { PostServerData::register().unwrap(); @@ -23,7 +28,10 @@ fn main() { axum::Server::bind(&addr) .serve( axum::Router::new() - .serve_dioxus_application("", ServeConfigBuilder::new(app, ())) + .serve_dioxus_application( + "", + ServeConfigBuilder::new(app, AppProps { count: 12345 }).build(), + ) .into_make_service(), ) .await @@ -32,8 +40,13 @@ fn main() { } } -fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); +#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)] +struct AppProps { + count: i32, +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || cx.props.count); let text = use_state(cx, || "...".to_string()); cx.render(rsx! { diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index d1e654fee..15a3ebe31 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -8,10 +8,15 @@ #![allow(non_snake_case)] use dioxus::prelude::*; use dioxus_server::prelude::*; +use serde::{Deserialize, Serialize}; fn main() { #[cfg(feature = "web")] - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + dioxus_web::launch_with_props( + app, + get_props_from_document().unwrap_or_default(), + dioxus_web::Config::new().hydrate(true), + ); #[cfg(feature = "ssr")] { use salvo::prelude::*; @@ -20,8 +25,10 @@ fn main() { tokio::runtime::Runtime::new() .unwrap() .block_on(async move { - let router = - Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ())); + let router = Router::new().serve_dioxus_application( + "", + ServeConfigBuilder::new(app, AppProps { count: 12345 }), + ); Server::new(TcpListener::bind("127.0.0.1:8080")) .serve(router) .await; @@ -29,8 +36,13 @@ fn main() { } } -fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); +#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)] +struct AppProps { + count: i32, +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || cx.props.count); let text = use_state(cx, || "...".to_string()); cx.render(rsx! { diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 51a627d16..a636dbc58 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -8,10 +8,15 @@ #![allow(non_snake_case)] use dioxus::prelude::*; use dioxus_server::prelude::*; +use serde::{Deserialize, Serialize}; fn main() { #[cfg(feature = "web")] - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + dioxus_web::launch_with_props( + app, + get_props_from_document().unwrap_or_default(), + dioxus_web::Config::new().hydrate(true), + ); #[cfg(feature = "ssr")] { PostServerData::register().unwrap(); @@ -19,14 +24,22 @@ fn main() { tokio::runtime::Runtime::new() .unwrap() .block_on(async move { - let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ())); + let routes = serve_dioxus_application( + "", + ServeConfigBuilder::new(app, AppProps { count: 12345 }), + ); warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; }); } } -fn app(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); +#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)] +struct AppProps { + count: i32, +} + +fn app(cx: Scope) -> Element { + let mut count = use_state(cx, || cx.props.count); let text = use_state(cx, || "...".to_string()); cx.render(rsx! { diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 2d16e9491..7fc47a8b3 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -184,7 +184,7 @@ pub trait DioxusRouterExt { /// todo!() /// } /// ``` - fn serve_dioxus_application( + fn serve_dioxus_application( self, server_fn_route: &'static str, cfg: impl Into>, @@ -229,7 +229,7 @@ where }) } - fn serve_dioxus_application( + fn serve_dioxus_application( mut self, server_fn_route: &'static str, cfg: impl Into>, @@ -294,7 +294,7 @@ where } } -async fn render_handler( +async fn render_handler( State((cfg, ssr_state)): State<(ServeConfig

, SSRState)>, ) -> impl IntoResponse { let rendered = ssr_state.render(&cfg); diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 402a0b0a0..ca11ff9ec 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -173,7 +173,7 @@ pub trait DioxusRouterExt { /// /// fn app(cx: Scope) -> Element {todo!()} /// ``` - fn serve_dioxus_application( + fn serve_dioxus_application( self, server_fn_path: &'static str, cfg: impl Into>, @@ -212,7 +212,7 @@ impl DioxusRouterExt for Router { }) } - fn serve_dioxus_application( + fn serve_dioxus_application( mut self, server_fn_route: &'static str, cfg: impl Into>, @@ -269,7 +269,7 @@ struct SSRHandler { } #[async_trait] -impl Handler for SSRHandler

{ +impl Handler for SSRHandler

{ async fn handle( &self, _req: &mut Request, diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index db88ac2b4..414160045 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -189,7 +189,7 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R /// todo!() /// } /// ``` -pub fn serve_dioxus_application( +pub fn serve_dioxus_application( server_fn_route: &'static str, cfg: impl Into>, ) -> BoxedFilter<(impl Reply,)> { diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index 525b636b3..e9f4ee63f 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -5,6 +5,8 @@ pub use adapters::*; +mod props_html; + mod adapters; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] mod hot_reload; @@ -23,6 +25,8 @@ pub mod prelude { pub use crate::adapters::salvo_adapter::*; #[cfg(feature = "warp")] pub use crate::adapters::warp_adapter::*; + #[cfg(not(feature = "ssr"))] + pub use crate::props_html::deserialize_props::get_props_from_document; #[cfg(feature = "ssr")] pub use crate::render::SSRState; #[cfg(feature = "ssr")] diff --git a/packages/server/src/props_html/deserialize_props.rs b/packages/server/src/props_html/deserialize_props.rs new file mode 100644 index 000000000..28b206ac5 --- /dev/null +++ b/packages/server/src/props_html/deserialize_props.rs @@ -0,0 +1,37 @@ +use serde::de::DeserializeOwned; + +use super::u16_from_char; + +#[allow(unused)] +pub(crate) fn serde_from_string(string: &str) -> Option { + let decompressed = string + .chars() + .flat_map(|c| { + let u = u16_from_char(c); + let u1 = (u >> 8) as u8; + let u2 = (u & 0xFF) as u8; + [u1, u2].into_iter() + }) + .collect::>(); + let (decompressed, _) = yazi::decompress(&decompressed, yazi::Format::Zlib).unwrap(); + + postcard::from_bytes(&decompressed).ok() +} + +#[cfg(not(feature = "ssr"))] +/// Get the props from the document. This is only available in the browser. +pub fn get_props_from_document() -> Option { + #[cfg(not(target_arch = "wasm32"))] + { + None + } + #[cfg(target_arch = "wasm32")] + { + let attribute = web_sys::window()? + .document()? + .get_element_by_id("dioxus-storage")? + .get_attribute("data-serialized")?; + + serde_from_string(&attribute) + } +} diff --git a/packages/server/src/props_html/mod.rs b/packages/server/src/props_html/mod.rs new file mode 100644 index 000000000..9e9b8721e --- /dev/null +++ b/packages/server/src/props_html/mod.rs @@ -0,0 +1,85 @@ +pub(crate) mod deserialize_props; + +pub(crate) mod serialize_props; + +#[test] +fn serialized_and_deserializes() { + use postcard::to_allocvec; + + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] + struct Data { + a: u32, + b: String, + bytes: Vec, + nested: Nested, + } + + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] + struct Nested { + a: u32, + b: u16, + c: u8, + } + + for x in 0..10usize { + for y in 0..10 { + let mut as_string = String::new(); + let data = vec![ + Data { + a: x as u32, + b: "hello".to_string(), + bytes: vec![0; x], + nested: Nested { + a: 1, + b: x as u16, + c: 3 + }, + }; + y + ]; + serialize_props::serde_to_writable(&data, &mut as_string).unwrap(); + + println!("{}", as_string); + println!( + "original size: {}", + std::mem::size_of::() * data.len() + ); + println!("serialized size: {}", to_allocvec(&data).unwrap().len()); + println!("compressed size: {}", as_string.len()); + + let decoded: Vec = deserialize_props::serde_from_string(&as_string).unwrap(); + assert_eq!(data, decoded); + } + } +} + +#[test] +fn encodes_and_decodes_bytes() { + for i in 0..(u16::MAX) { + let c = u16_to_char(i); + let i2 = u16_from_char(c); + assert_eq!(i, i2); + } +} + +#[allow(unused)] +pub(crate) fn u16_to_char(u: u16) -> char { + let u = u as u32; + let mapped = if u <= 0xD7FF { + u + } else { + 0xE000 + (u - 0xD7FF) + }; + char::from_u32(mapped).unwrap() +} + +#[allow(unused)] +pub(crate) fn u16_from_char(c: char) -> u16 { + let c = c as u32; + let mapped = if c <= 0xD7FF { + c + } else { + 0xD7FF + (c - 0xE000) + }; + mapped as u16 +} diff --git a/packages/server/src/props_html/serialize_props.rs b/packages/server/src/props_html/serialize_props.rs new file mode 100644 index 000000000..f1282f07f --- /dev/null +++ b/packages/server/src/props_html/serialize_props.rs @@ -0,0 +1,37 @@ +use serde::Serialize; + +use super::u16_to_char; + +#[allow(unused)] +pub(crate) fn serde_to_writable( + value: &T, + mut write_to: impl std::fmt::Write, +) -> std::fmt::Result { + let serialized = postcard::to_allocvec(value).unwrap(); + let compressed = yazi::compress( + &serialized, + yazi::Format::Zlib, + yazi::CompressionLevel::BestSize, + ) + .unwrap(); + for array in compressed.chunks(2) { + let w = if array.len() == 2 { + [array[0], array[1]] + } else { + [array[0], 0] + }; + write_to.write_char(u16_to_char((w[0] as u16) << 8 | (w[1] as u16)))?; + } + Ok(()) +} + +#[cfg(feature = "ssr")] +/// Encode data into a element. This is inteded to be used in the server to send data to the client. +pub(crate) fn encode_in_element( + data: T, + mut write_to: impl std::fmt::Write, +) -> std::fmt::Result { + write_to.write_str(r#""#) +} diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 8328be317..0f61a3a0f 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -24,7 +24,7 @@ impl Default for SSRState { impl SSRState { /// Render the application to HTML. - pub fn render(&self, cfg: &ServeConfig

) -> String { + pub fn render(&self, cfg: &ServeConfig

) -> String { let ServeConfig { app, props, index, .. } = cfg; @@ -41,6 +41,9 @@ impl SSRState { let _ = renderer.render_to(&mut html, &vdom); + // serialize the props + let _ = crate::props_html::serialize_props::encode_in_element(&cfg.props, &mut html); + html += &index.post_main; html From 581a4648de58f3db9a5b617a39a9b73d7f639bf9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 28 Apr 2023 18:01:21 -0500 Subject: [PATCH 478/895] document get_root_props_from_document --- packages/server/examples/axum-hello-world/src/main.rs | 2 +- packages/server/examples/salvo-hello-world/src/main.rs | 2 +- packages/server/examples/warp-hello-world/src/main.rs | 2 +- packages/server/src/lib.rs | 2 +- packages/server/src/props_html/deserialize_props.rs | 4 +++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index b5553f7a2..5b3323ec4 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -14,7 +14,7 @@ fn main() { #[cfg(feature = "web")] dioxus_web::launch_with_props( app, - get_props_from_document().unwrap_or_default(), + get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); #[cfg(feature = "ssr")] diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index 15a3ebe31..a6e33dc63 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -14,7 +14,7 @@ fn main() { #[cfg(feature = "web")] dioxus_web::launch_with_props( app, - get_props_from_document().unwrap_or_default(), + get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); #[cfg(feature = "ssr")] diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index a636dbc58..4929af0c8 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -14,7 +14,7 @@ fn main() { #[cfg(feature = "web")] dioxus_web::launch_with_props( app, - get_props_from_document().unwrap_or_default(), + get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); #[cfg(feature = "ssr")] diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index e9f4ee63f..c5ad196bc 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -26,7 +26,7 @@ pub mod prelude { #[cfg(feature = "warp")] pub use crate::adapters::warp_adapter::*; #[cfg(not(feature = "ssr"))] - pub use crate::props_html::deserialize_props::get_props_from_document; + pub use crate::props_html::deserialize_props::get_root_props_from_document; #[cfg(feature = "ssr")] pub use crate::render::SSRState; #[cfg(feature = "ssr")] diff --git a/packages/server/src/props_html/deserialize_props.rs b/packages/server/src/props_html/deserialize_props.rs index 28b206ac5..64f2181ab 100644 --- a/packages/server/src/props_html/deserialize_props.rs +++ b/packages/server/src/props_html/deserialize_props.rs @@ -20,7 +20,9 @@ pub(crate) fn serde_from_string(string: &str) -> Option #[cfg(not(feature = "ssr"))] /// Get the props from the document. This is only available in the browser. -pub fn get_props_from_document() -> Option { +/// +/// When dioxus-server renders the page, it will serialize the root props and put them in the document. This function gets them from the document. +pub fn get_root_props_from_document() -> Option { #[cfg(not(target_arch = "wasm32"))] { None From 3317dc3e177e80ff62ba1b3a5f66e942d222f051 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 29 Apr 2023 07:58:43 -0500 Subject: [PATCH 479/895] fix the link to tui widgets in the guide --- docs/guide/src/en/custom_renderer/index.md | 2 +- docs/guide/src/en/getting_started/tui.md | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/guide/src/en/custom_renderer/index.md b/docs/guide/src/en/custom_renderer/index.md index 2d4ddb759..b531593dc 100644 --- a/docs/guide/src/en/custom_renderer/index.md +++ b/docs/guide/src/en/custom_renderer/index.md @@ -15,7 +15,7 @@ Essentially, your renderer needs to process edits and generate events to update Internally, Dioxus handles the tree relationship, diffing, memory management, and the event system, leaving as little as possible required for renderers to implement themselves. -For reference, check out the [javascript interpreter](https://github.com/DioxusLabs/dioxus/tree/master/packages/interpreter) or [tui renderer](https://github.com/DioxusLabs/dioxus/tree/master/packages/tui) as a starting point for your custom renderer. +For reference, check out the [javascript interpreter](https://github.com/DioxusLabs/dioxus/tree/master/packages/interpreter) or [tui renderer](https://github.com/DioxusLabs/dioxus/tree/master/packages/dioxus-tui) as a starting point for your custom renderer. ## Templates diff --git a/docs/guide/src/en/getting_started/tui.md b/docs/guide/src/en/getting_started/tui.md index e49cb84a8..4e8d36cf9 100644 --- a/docs/guide/src/en/getting_started/tui.md +++ b/docs/guide/src/en/getting_started/tui.md @@ -12,14 +12,12 @@ TUI support is currently quite experimental. But, if you're willing to venture i - It uses flexbox for the layout - It only supports a subset of the attributes and elements -- Regular widgets will not work in the tui render, but the tui renderer has its own widget components that start with a capital letter. See the [widgets example](https://github.com/DioxusLabs/dioxus/blob/master/packages/tui/examples/widgets.rs) +- Regular widgets will not work in the tui render, but the tui renderer has its own widget components that start with a capital letter. See the [widgets example](https://github.com/DioxusLabs/dioxus/blob/master/packages/dioxus-tui/examples/widgets.rs) - 1px is one character line height. Your regular CSS px does not translate - If your app panics, your terminal is wrecked. This will be fixed eventually - ## Getting Set up - Start by making a new package and adding Dioxus and the TUI renderer as dependancies. ```shell From 74cb70590c1b50d8f9bbaf82411e6c3c8a8223e0 Mon Sep 17 00:00:00 2001 From: stephenandary Date: Sat, 29 Apr 2023 11:44:28 -0400 Subject: [PATCH 480/895] WIP - Initial commit of devcontainer --- .devcontainer/devcontainer.json | 28 +++++++++++++++++++ .../linux/devcontainer-feature.json | 4 +++ .devcontainer/local-features/linux/install.sh | 6 ++++ 3 files changed, 38 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/local-features/linux/devcontainer-feature.json create mode 100644 .devcontainer/local-features/linux/install.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..1c5278332 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +{ + "name": "dioxus", + "image": "mcr.microsoft.com/devcontainers/rust:latest", + "features": { + "ghcr.io/devcontainers/features/common-utils:2": {}, + "./local-features/linux": {} + }, + "containerEnv": { + "RUST_LOG": "INFO" + }, + "customizations": { + "vscode": { + "settings": { + "files.watcherExclude": { + "**/target/**": true + }, + "[rust]": { + "editor.formatOnSave": true + } + }, + "extensions": [ + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + "serayuzgur.crates" + ] + } + } +} \ No newline at end of file diff --git a/.devcontainer/local-features/linux/devcontainer-feature.json b/.devcontainer/local-features/linux/devcontainer-feature.json new file mode 100644 index 000000000..daba5bc1f --- /dev/null +++ b/.devcontainer/local-features/linux/devcontainer-feature.json @@ -0,0 +1,4 @@ +{ + "id": "linux", + "version": "0.0.1" +} \ No newline at end of file diff --git a/.devcontainer/local-features/linux/install.sh b/.devcontainer/local-features/linux/install.sh new file mode 100644 index 000000000..8f9ad5e1a --- /dev/null +++ b/.devcontainer/local-features/linux/install.sh @@ -0,0 +1,6 @@ +#!/bin/bash +echo "Update Apt Database" +sudo apt-get update + +echo "Install Webkit Dependencies" +sudo apt-get -qq install build-essential libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev From 7ff5d356d5cdfbf2709fb7120e7f7088dcb6a658 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 29 Apr 2023 17:04:54 -0500 Subject: [PATCH 481/895] allow server functions to read request and modify responce --- packages/server/Cargo.toml | 9 +- .../examples/axum-hello-world/Cargo.toml | 7 + .../examples/axum-hello-world/src/main.rs | 9 +- .../server/examples/axum-router/Cargo.toml | 7 + .../examples/salvo-hello-world/Cargo.toml | 7 + .../examples/salvo-hello-world/src/main.rs | 11 +- .../examples/warp-hello-world/Cargo.toml | 7 + .../examples/warp-hello-world/src/main.rs | 11 +- packages/server/src/adapters/axum_adapter.rs | 46 ++-- packages/server/src/adapters/salvo_adapter.rs | 62 ++++-- packages/server/src/adapters/warp_adapter.rs | 145 ++++++++----- packages/server/src/lib.rs | 6 +- packages/server/src/render.rs | 15 +- packages/server/src/server_context.rs | 204 +++++++++++++----- 14 files changed, 387 insertions(+), 159 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index 2e20cdc81..b6293993c 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -23,7 +23,6 @@ http-body = { version = "0.4.5", optional = true } # axum axum = { version = "0.6.1", features = ["ws"], optional = true } tower-http = { version = "0.4.0", optional = true, features = ["fs"] } -hyper = { version = "0.14.25", optional = true } axum-macros = "0.3.7" # salvo @@ -33,6 +32,8 @@ serde = "1.0.159" # Dioxus + SSR dioxus-core = { path = "../core", version = "^0.3.0" } dioxus-ssr = { path = "../ssr", version = "^0.3.0", optional = true } +hyper = { version = "0.14.25", optional = true } +http = { version = "0.2.9", optional = true } log = "0.4.17" once_cell = "1.17.1" @@ -57,6 +58,6 @@ web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "Ht default = ["hot-reload"] hot-reload = ["serde_json", "tokio-stream", "futures-util"] warp = ["dep:warp", "http-body", "ssr"] -axum = ["dep:axum", "tower-http", "hyper", "ssr"] -salvo = ["dep:salvo", "hyper", "ssr"] -ssr = ["server_fn/ssr", "tokio", "dioxus-ssr"] +axum = ["dep:axum", "tower-http", "ssr"] +salvo = ["dep:salvo", "ssr"] +ssr = ["server_fn/ssr", "tokio", "dioxus-ssr", "hyper", "http"] diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index fd1f051d1..b2c14561d 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -18,3 +18,10 @@ serde = "1.0.159" default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum"] web = ["dioxus-web"] + +[profile.release] +lto = true +panic = "abort" +opt-level = 3 +strip = true +codegen-units = 1 diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index 5b3323ec4..6b6f32db7 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -56,11 +56,12 @@ fn app(cx: Scope) -> Element { button { onclick: move |_| { to_owned![text]; + let sc = cx.sc(); async move { if let Ok(data) = get_server_data().await { println!("Client received: {}", data); text.set(data.clone()); - post_server_data(data).await.unwrap(); + post_server_data(sc, data).await.unwrap(); } } }, @@ -71,8 +72,12 @@ fn app(cx: Scope) -> Element { } #[server(PostServerData)] -async fn post_server_data(data: String) -> Result<(), ServerFnError> { +async fn post_server_data(cx: DioxusServerContext, data: String) -> Result<(), ServerFnError> { + // The server context contains information about the current request and allows you to modify the response. + cx.responce_headers_mut() + .insert("Set-Cookie", "foo=bar".parse().unwrap()); println!("Server received: {}", data); + println!("Request parts are {:?}", cx.request_parts()); Ok(()) } diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml index 699779763..3e137d8f6 100644 --- a/packages/server/examples/axum-router/Cargo.toml +++ b/packages/server/examples/axum-router/Cargo.toml @@ -21,3 +21,10 @@ http = { version = "0.2.9", optional = true } default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum", "tower-http", "http"] web = ["dioxus-web", "dioxus-router/web"] + +[profile.release] +lto = true +panic = "abort" +opt-level = 3 +strip = true +codegen-units = 1 diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 1ddf52915..9146ce3e2 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -18,3 +18,10 @@ salvo = { version = "0.37.9", optional = true } default = ["web"] ssr = ["salvo", "tokio", "dioxus-server/salvo"] web = ["dioxus-web"] + +[profile.release] +lto = true +panic = "abort" +opt-level = 3 +strip = true +codegen-units = 1 diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index a6e33dc63..ff1081077 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -44,6 +44,7 @@ struct AppProps { fn app(cx: Scope) -> Element { let mut count = use_state(cx, || cx.props.count); let text = use_state(cx, || "...".to_string()); + let server_context = cx.sc(); cx.render(rsx! { h1 { "High-Five counter: {count}" } @@ -51,12 +52,12 @@ fn app(cx: Scope) -> Element { button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| { - to_owned![text]; + to_owned![text, server_context]; async move { if let Ok(data) = get_server_data().await { println!("Client received: {}", data); text.set(data.clone()); - post_server_data(data).await.unwrap(); + post_server_data(server_context, data).await.unwrap(); } } }, @@ -67,8 +68,12 @@ fn app(cx: Scope) -> Element { } #[server(PostServerData)] -async fn post_server_data(data: String) -> Result<(), ServerFnError> { +async fn post_server_data(cx: DioxusServerContext, data: String) -> Result<(), ServerFnError> { + // The server context contains information about the current request and allows you to modify the response. + cx.responce_headers_mut() + .insert("Set-Cookie", "foo=bar".parse().unwrap()); println!("Server received: {}", data); + println!("Request parts are {:?}", cx.request_parts()); Ok(()) } diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index cbd8606dd..e182494b0 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -18,3 +18,10 @@ warp = { version = "0.3.3", optional = true } default = ["web"] ssr = ["warp", "tokio", "dioxus-server/warp"] web = ["dioxus-web"] + +[profile.release] +lto = true +panic = "abort" +opt-level = 3 +strip = true +codegen-units = 1 diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 4929af0c8..04684f803 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -41,6 +41,7 @@ struct AppProps { fn app(cx: Scope) -> Element { let mut count = use_state(cx, || cx.props.count); let text = use_state(cx, || "...".to_string()); + let server_context = cx.sc(); cx.render(rsx! { h1 { "High-Five counter: {count}" } @@ -48,12 +49,12 @@ fn app(cx: Scope) -> Element { button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| { - to_owned![text]; + to_owned![text, server_context]; async move { if let Ok(data) = get_server_data().await { println!("Client received: {}", data); text.set(data.clone()); - post_server_data(data).await.unwrap(); + post_server_data(server_context, data).await.unwrap(); } } }, @@ -64,8 +65,12 @@ fn app(cx: Scope) -> Element { } #[server(PostServerData)] -async fn post_server_data(data: String) -> Result<(), ServerFnError> { +async fn post_server_data(cx: DioxusServerContext, data: String) -> Result<(), ServerFnError> { + // The server context contains information about the current request and allows you to modify the response. + cx.responce_headers_mut() + .insert("Set-Cookie", "foo=bar".parse().unwrap()); println!("Server received: {}", data); + println!("Request parts are {:?}", cx.request_parts()); Ok(()) } diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 7fc47a8b3..1b572c804 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -57,16 +57,17 @@ use axum::{ body::{self, Body, BoxBody, Full}, - extract::RawQuery, extract::{State, WebSocketUpgrade}, handler::Handler, - http::{HeaderMap, Request, Response, StatusCode}, + http::{Request, Response, StatusCode}, response::IntoResponse, routing::{get, post}, Router, }; +use dioxus_core::VirtualDom; use server_fn::{Encoding, Payload, ServerFunctionRegistry}; use std::error::Error; +use std::sync::Arc; use tokio::task::spawn_blocking; use crate::{ @@ -223,8 +224,11 @@ where fn register_server_fns(self, server_fn_route: &'static str) -> Self { self.register_server_fns_with_handler(server_fn_route, |func| { - move |headers: HeaderMap, RawQuery(query): RawQuery, body: Request| async move { - server_fn_handler((), func.clone(), headers, query, body).await + move |req: Request| async move { + let (parts, body) = req.into_parts(); + let parts: Arc = Arc::new(parts.into()); + let server_context = DioxusServerContext::new(parts.clone()); + server_fn_handler(server_context, func.clone(), parts, body).await } }) } @@ -296,44 +300,54 @@ where async fn render_handler( State((cfg, ssr_state)): State<(ServeConfig

, SSRState)>, + request: Request, ) -> impl IntoResponse { - let rendered = ssr_state.render(&cfg); + let (parts, _) = request.into_parts(); + let parts: Arc = Arc::new(parts.into()); + let server_context = DioxusServerContext::new(parts); + let mut vdom = + VirtualDom::new_with_props(cfg.app, cfg.props.clone()).with_root_context(server_context); + let _ = vdom.rebuild(); + + let rendered = ssr_state.render_vdom(&vdom, &cfg); Full::from(rendered) } /// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. pub async fn server_fn_handler( - server_context: impl Into, + server_context: DioxusServerContext, function: ServerFunction, - headers: HeaderMap, - query: Option, - req: Request, + parts: Arc, + body: Body, ) -> impl IntoResponse { - let server_context = server_context.into(); - let (_, body) = req.into_parts(); let body = hyper::body::to_bytes(body).await; - let Ok(body)=body else { + let Ok(body) = body else { return report_err(body.err().unwrap()); }; // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); + let query_string = parts.uri.query().unwrap_or_default().to_string(); spawn_blocking({ move || { tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") .block_on(async { - let query = &query.unwrap_or_default().into(); + let query = &query_string.into(); let data = match &function.encoding { Encoding::Url | Encoding::Cbor => &body, Encoding::GetJSON | Encoding::GetCBOR => query, }; - let resp = match (function.trait_obj)(server_context, &data).await { + let resp = match (function.trait_obj)(server_context.clone(), &data).await { Ok(serialized) => { // if this is Accept: application/json then send a serialized JSON response - let accept_header = - headers.get("Accept").and_then(|value| value.to_str().ok()); + let accept_header = parts + .headers + .get("Accept") + .and_then(|value| value.to_str().ok()); let mut res = Response::builder(); + *res.headers_mut().expect("empty responce should be valid") = + server_context.take_responce_headers(); if accept_header == Some("application/json") || accept_header == Some( diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index ca11ff9ec..6ed4c2b3e 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -50,8 +50,7 @@ //! } //! ``` -use std::error::Error; - +use dioxus_core::VirtualDom; use hyper::{http::HeaderValue, StatusCode}; use salvo::{ async_trait, handler, @@ -59,6 +58,8 @@ use salvo::{ Depot, FlowCtrl, Handler, Request, Response, Router, }; use server_fn::{Encoding, Payload, ServerFunctionRegistry}; +use std::error::Error; +use std::sync::Arc; use tokio::task::spawn_blocking; use crate::{ @@ -172,7 +173,7 @@ pub trait DioxusRouterExt { /// } /// /// fn app(cx: Scope) -> Element {todo!()} - /// ``` + /// ``` fn serve_dioxus_application( self, server_fn_path: &'static str, @@ -264,6 +265,17 @@ impl DioxusRouterExt for Router { } } +/// Extracts the parts of a request that are needed for server functions. This will take parts of the request and replace them with empty values. +pub fn extract_parts(req: &mut Request) -> RequestParts { + RequestParts { + method: std::mem::take(req.method_mut()), + uri: std::mem::take(req.uri_mut()), + version: req.version(), + headers: std::mem::take(req.headers_mut()), + extensions: std::mem::take(req.extensions_mut()), + } +} + struct SSRHandler { cfg: ServeConfig

, } @@ -272,7 +284,7 @@ struct SSRHandler { impl Handler for SSRHandler

{ async fn handle( &self, - _req: &mut Request, + req: &mut Request, depot: &mut Depot, res: &mut Response, _flow: &mut FlowCtrl, @@ -285,7 +297,16 @@ impl Handler for SSRHandler depot.inject(renderer.clone()); renderer }; - res.write_body(renderer_pool.render(&self.cfg)).unwrap(); + let parts: Arc = Arc::new(extract_parts(req)); + let server_context = DioxusServerContext::new(parts); + let mut vdom = VirtualDom::new_with_props(self.cfg.app, self.cfg.props.clone()) + .with_root_context(server_context.clone()); + let _ = vdom.rebuild(); + + res.write_body(renderer_pool.render_vdom(&vdom, &self.cfg)) + .unwrap(); + + *res.headers_mut() = server_context.take_responce_headers(); } } @@ -314,17 +335,6 @@ impl ServerFnHandler { function, } = self; - let body = hyper::body::to_bytes(req.body_mut().unwrap()).await; - let Ok(body)=body else { - handle_error(body.err().unwrap(), res); - return; - }; - let headers = req.headers(); - - // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime - let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); - let function = function.clone(); - let server_context = server_context.clone(); let query = req .uri() .query() @@ -332,7 +342,22 @@ impl ServerFnHandler { .as_bytes() .to_vec() .into(); + let body = hyper::body::to_bytes(req.body_mut().unwrap()).await; + let Ok(body)=body else { + handle_error(body.err().unwrap(), res); + return; + }; + let headers = req.headers(); + let accept_header = headers.get("Accept").cloned(); + + let parts = Arc::new(extract_parts(req)); + + // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime + let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); spawn_blocking({ + let function = function.clone(); + let mut server_context = server_context.clone(); + server_context.parts = parts; move || { tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") @@ -349,10 +374,13 @@ impl ServerFnHandler { }); let result = resp_rx.await.unwrap(); + // Set the headers from the server context + *res.headers_mut() = server_context.take_responce_headers(); + match result { Ok(serialized) => { // if this is Accept: application/json then send a serialized JSON response - let accept_header = headers.get("Accept").and_then(|value| value.to_str().ok()); + let accept_header = accept_header.as_ref().and_then(|value| value.to_str().ok()); if accept_header == Some("application/json") || accept_header == Some( diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 414160045..31d4daba4 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -51,13 +51,16 @@ use crate::{ prelude::*, render::SSRState, serve_config::ServeConfig, server_fn::DioxusServerFnRegistry, }; +use dioxus_core::VirtualDom; use server_fn::{Encoding, Payload, ServerFunctionRegistry}; use std::error::Error; +use std::sync::Arc; use tokio::task::spawn_blocking; +use warp::path::FullPath; use warp::{ filters::BoxedFilter, http::{Response, StatusCode}, - hyper::{body::Bytes, HeaderMap}, + hyper::body::Bytes, path, Filter, Reply, }; @@ -125,48 +128,16 @@ where /// ``` pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { register_server_fns_with_handler(server_fn_route, |full_route, func| { - let func2 = func.clone(); - let func3 = func.clone(); path(full_route.clone()) - .and(warp::filters::method::get()) - .and(warp::header::headers_cloned()) - .and(warp::filters::query::raw()) + .and(warp::post().or(warp::get()).unify()) + .and(request_parts()) .and(warp::body::bytes()) - .and_then(move |headers, query, body| { + .and_then(move |parts, bytes| { let func = func.clone(); async move { - server_fn_handler( - DioxusServerContext::default(), - func, - headers, - Some(query), - body, - ) - .await + server_fn_handler(DioxusServerContext::default(), func, parts, bytes).await } }) - .or(path(full_route.clone()) - .and(warp::filters::method::get()) - .and(warp::header::headers_cloned()) - .and(warp::body::bytes()) - .and_then(move |headers, body| { - let func = func2.clone(); - async move { - server_fn_handler(DioxusServerContext::default(), func, headers, None, body) - .await - } - })) - .or(path(full_route) - .and(warp::filters::method::post()) - .and(warp::header::headers_cloned()) - .and(warp::body::bytes()) - .and_then(move |headers, body| { - let func = func3.clone(); - async move { - server_fn_handler(DioxusServerContext::default(), func, headers, None, body) - .await - } - })) }) } @@ -199,18 +170,71 @@ pub fn serve_dioxus_application( + cfg: ServeConfig

, +) -> impl Filter + Clone { + warp::get() + .and(request_parts()) + .and(with_ssr_state()) + .map(move |parts, renderer: SSRState| { + let parts = Arc::new(parts); + + let server_context = DioxusServerContext::new(parts); + + let mut vdom = VirtualDom::new_with_props(cfg.app, cfg.props.clone()) + .with_root_context(server_context.clone()); + let _ = vdom.rebuild(); + + let html = renderer.render_vdom(&vdom, &cfg); + + let mut res = Response::builder(); + + *res.headers_mut().expect("empty request should be valid") = + server_context.take_responce_headers(); + + res.header("Content-Type", "text/html") + .body(Bytes::from(html)) + .unwrap() + }) +} + +/// An extractor for the request parts (used in [DioxusServerContext]). This will extract the method, uri, query, and headers from the request. +pub fn request_parts( +) -> impl Filter + Clone { + warp::method() + .and(warp::filters::path::full()) + .and( + warp::filters::query::raw() + .or(warp::any().map(String::new)) + .unify(), + ) + .and(warp::header::headers_cloned()) + .and_then(move |method, path: FullPath, query, headers| async move { + http::uri::Builder::new() + .path_and_query(format!("{}?{}", path.as_str(), query)) + .build() + .map_err(|err| { + warp::reject::custom(FailedToReadBody(format!("Failed to build uri: {}", err))) + }) + .map(|uri| RequestParts { + method, + uri, + headers, + ..Default::default() + }) + }) +} + fn with_ssr_state() -> impl Filter + Clone { - let renderer = SSRState::default(); - warp::any().map(move || renderer.clone()) + let state = SSRState::default(); + warp::any().map(move || state.clone()) } #[derive(Debug)] @@ -227,29 +251,46 @@ impl warp::reject::Reject for RecieveFailed {} pub async fn server_fn_handler( server_context: impl Into, function: ServerFunction, - headers: HeaderMap, - query: Option, + parts: RequestParts, body: Bytes, ) -> Result, warp::Rejection> { - let server_context = server_context.into(); + let mut server_context = server_context.into(); + + let parts = Arc::new(parts); + + server_context.parts = parts.clone(); + // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime let (resp_tx, resp_rx) = tokio::sync::oneshot::channel(); spawn_blocking({ move || { tokio::runtime::Runtime::new() .expect("couldn't spawn runtime") - .block_on(async { - let query = &query.unwrap_or_default().into(); + .block_on(async move { + let query = parts + .uri + .query() + .unwrap_or_default() + .as_bytes() + .to_vec() + .into(); let data = match &function.encoding { Encoding::Url | Encoding::Cbor => &body, - Encoding::GetJSON | Encoding::GetCBOR => query, + Encoding::GetJSON | Encoding::GetCBOR => &query, }; - let resp = match (function.trait_obj)(server_context, &data).await { + let resp = match (function.trait_obj)(server_context.clone(), data).await { Ok(serialized) => { // if this is Accept: application/json then send a serialized JSON response - let accept_header = - headers.get("Accept").and_then(|value| value.to_str().ok()); + let accept_header = parts + .headers + .get("Accept") + .as_ref() + .and_then(|value| value.to_str().ok()); let mut res = Response::builder(); + + *res.headers_mut().expect("empty request should be valid") = + server_context.take_responce_headers(); + if accept_header == Some("application/json") || accept_header == Some( diff --git a/packages/server/src/lib.rs b/packages/server/src/lib.rs index c5ad196bc..8d18dca2a 100644 --- a/packages/server/src/lib.rs +++ b/packages/server/src/lib.rs @@ -30,8 +30,10 @@ pub mod prelude { #[cfg(feature = "ssr")] pub use crate::render::SSRState; #[cfg(feature = "ssr")] - pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; - pub use crate::server_context::DioxusServerContext; + pub use crate::serve_config::{ ServeConfig, ServeConfigBuilder}; + #[cfg(feature = "ssr")] + pub use crate::server_context::{RequestParts}; + pub use crate::server_context::{ DioxusServerContext, HasServerContext}; pub use crate::server_fn::ServerFn; #[cfg(feature = "ssr")] pub use crate::server_fn::{ServerFnTraitObj, ServerFunction}; diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 0f61a3a0f..e8f6a67ec 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -26,20 +26,31 @@ impl SSRState { /// Render the application to HTML. pub fn render(&self, cfg: &ServeConfig

) -> String { let ServeConfig { - app, props, index, .. + app, props, .. } = cfg; let mut vdom = VirtualDom::new_with_props(*app, props.clone()); let _ = vdom.rebuild(); + self.render_vdom(&vdom, cfg) + } + + /// Render a VirtualDom to HTML. + pub fn render_vdom( + &self, + vdom: &VirtualDom, + cfg: &ServeConfig

, + ) -> String { + let ServeConfig { index, .. } = cfg; + let mut renderer = self.renderers.pull(pre_renderer); let mut html = String::new(); html += &index.pre_main; - let _ = renderer.render_to(&mut html, &vdom); + let _ = renderer.render_to(&mut html, vdom); // serialize the props let _ = crate::props_html::serialize_props::encode_in_element(&cfg.props, &mut html); diff --git a/packages/server/src/server_context.rs b/packages/server/src/server_context.rs index 7e2a494c5..aff9ede35 100644 --- a/packages/server/src/server_context.rs +++ b/packages/server/src/server_context.rs @@ -1,72 +1,160 @@ -use std::sync::{Arc, PoisonError, RwLock, RwLockWriteGuard}; +use dioxus_core::ScopeState; -use anymap::{any::Any, Map}; +/// A trait for an object that contains a server context +pub trait HasServerContext { + /// Get the server context from the state + fn server_context(&self) -> DioxusServerContext; -type SendSyncAnyMap = Map; - -/// A shared context for server functions. -/// This allows you to pass data between your server framework and the server functions. This can be used to pass request information or information about the state of the server. For example, you could pass authentication data though this context to your server functions. -#[derive(Clone)] -pub struct DioxusServerContext { - shared_context: Arc>, + /// A shortcut for `self.server_context()` + fn sc(&self) -> DioxusServerContext { + self.server_context() + } } -impl Default for DioxusServerContext { - fn default() -> Self { - Self { - shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), +impl HasServerContext for &ScopeState { + fn server_context(&self) -> DioxusServerContext { + #[cfg(feature = "ssr")] + { + self.consume_context().expect("No server context found") + } + #[cfg(not(feature = "ssr"))] + { + DioxusServerContext {} } } } -impl DioxusServerContext { - /// Clone a value from the shared server context - pub fn get(&self) -> Option { - self.shared_context.read().ok()?.get::().cloned() - } +/// A shared context for server functions that contains infomation about the request and middleware state. +/// This allows you to pass data between your server framework and the server functions. This can be used to pass request information or information about the state of the server. For example, you could pass authentication data though this context to your server functions. +/// +/// You should not construct this directly inside components. Instead use the `HasServerContext` trait to get the server context from the scope. +#[derive(Clone)] +pub struct DioxusServerContext { + #[cfg(feature = "ssr")] + shared_context: std::sync::Arc< + std::sync::RwLock>, + >, + #[cfg(feature = "ssr")] + headers: std::sync::Arc>, + #[cfg(feature = "ssr")] + pub(crate) parts: std::sync::Arc, +} - /// Insert a value into the shared server context - pub fn insert( - &mut self, - value: T, - ) -> Result<(), PoisonError>> { - self.shared_context - .write() - .map(|mut map| map.insert(value)) - .map(|_| ()) +#[allow(clippy::derivable_impls)] +impl Default for DioxusServerContext { + fn default() -> Self { + Self { + #[cfg(feature = "ssr")] + shared_context: std::sync::Arc::new(std::sync::RwLock::new(anymap::Map::new())), + #[cfg(feature = "ssr")] + headers: Default::default(), + #[cfg(feature = "ssr")] + parts: Default::default(), + } } } -/// Generate a server context from a tuple of values -macro_rules! server_context { - ($({$(($name:ident: $ty:ident)),*}),*) => { - $( - #[allow(unused_mut)] - impl< $($ty: Send + Sync + 'static),* > From<($($ty,)*)> for $crate::server_context::DioxusServerContext { - fn from(( $($name,)* ): ($($ty,)*)) -> Self { - let mut context = $crate::server_context::DioxusServerContext::default(); - $(context.insert::<$ty>($name).unwrap();)* - context - } +#[cfg(feature = "ssr")] +pub use server_fn_impl::*; + +#[cfg(feature = "ssr")] +mod server_fn_impl { + use super::*; + use std::sync::LockResult; + use std::sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; + + use anymap::{any::Any, Map}; + type SendSyncAnyMap = Map; + + impl DioxusServerContext { + /// Create a new server context from a request + pub fn new(parts: impl Into>) -> Self { + Self { + parts: parts.into(), + shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), + headers: Default::default(), } - )* - }; -} + } -server_context!( - {}, - {(a: A)}, - {(a: A), (b: B)}, - {(a: A), (b: B), (c: C)}, - {(a: A), (b: B), (c: C), (d: D)}, - {(a: A), (b: B), (c: C), (d: D), (e: E)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L), (m: M)}, - {(a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I), (j: J), (k: K), (l: L), (m: M), (n: N)} -); + /// Clone a value from the shared server context + pub fn get(&self) -> Option { + self.shared_context.read().ok()?.get::().cloned() + } + + /// Insert a value into the shared server context + pub fn insert( + &mut self, + value: T, + ) -> Result<(), PoisonError>> { + self.shared_context + .write() + .map(|mut map| map.insert(value)) + .map(|_| ()) + } + + /// Get the headers from the server context + pub fn responce_headers(&self) -> RwLockReadGuard<'_, hyper::header::HeaderMap> { + self.try_responce_headers() + .expect("Failed to get headers from server context") + } + + /// Try to get the headers from the server context + pub fn try_responce_headers( + &self, + ) -> LockResult> { + self.headers.read() + } + + /// Get the headers mutably from the server context + pub fn responce_headers_mut(&self) -> RwLockWriteGuard<'_, hyper::header::HeaderMap> { + self.try_responce_headers_mut() + .expect("Failed to get headers mutably from server context") + } + + /// Try to get the headers mut from the server context + pub fn try_responce_headers_mut( + &self, + ) -> LockResult> { + self.headers.write() + } + + pub(crate) fn take_responce_headers(&self) -> hyper::header::HeaderMap { + let mut headers = self.headers.write().unwrap(); + std::mem::take(&mut *headers) + } + + /// Get the request that triggered: + /// - The initial SSR render if called from a ScopeState or ServerFn + /// - The server function to be called if called from a server function after the initial render + pub fn request_parts(&self) -> &RequestParts { + &self.parts + } + } + + /// Associated parts of an HTTP Request + #[derive(Debug, Default)] + pub struct RequestParts { + /// The request's method + pub method: http::Method, + /// The request's URI + pub uri: http::Uri, + /// The request's version + pub version: http::Version, + /// The request's headers + pub headers: http::HeaderMap, + /// The request's extensions + pub extensions: http::Extensions, + } + + impl From for RequestParts { + fn from(parts: http::request::Parts) -> Self { + Self { + method: parts.method, + uri: parts.uri, + version: parts.version, + headers: parts.headers, + extensions: parts.extensions, + } + } + } +} From 64c7fda201fa718ca2d80c83243d6b537a8e8b53 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 29 Apr 2023 17:32:16 -0500 Subject: [PATCH 482/895] fix warp release builds --- packages/server/src/adapters/warp_adapter.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 31d4daba4..5e9d23562 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -360,12 +360,10 @@ pub fn connect_hot_reload() -> impl Filter Date: Sat, 29 Apr 2023 20:42:47 -0500 Subject: [PATCH 483/895] Remove console.log --- packages/interpreter/src/sledgehammer_bindings.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/interpreter/src/sledgehammer_bindings.rs b/packages/interpreter/src/sledgehammer_bindings.rs index a15d7bc81..2cb148e89 100644 --- a/packages/interpreter/src/sledgehammer_bindings.rs +++ b/packages/interpreter/src/sledgehammer_bindings.rs @@ -118,7 +118,6 @@ mod js { nodes[id] = node; } export function get_node(id) { - console.log(nodes, id); return nodes[id]; } export function initilize(root, handler) { From f6cd48c6123204c4979b154516d46876ec61d59a Mon Sep 17 00:00:00 2001 From: Antonio Curavalea Date: Sun, 30 Apr 2023 23:13:46 +0300 Subject: [PATCH 484/895] feat: open browser during serve with "--open" --- Cargo.lock | 36 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/cli/cfg.rs | 5 +++++ src/cli/serve/mod.rs | 2 +- src/server/mod.rs | 39 ++++++++++++++++++++++++++++----------- 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41d9f8eb5..abf1ce3a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -722,6 +722,7 @@ dependencies = [ "log", "mlua", "notify", + "open", "proc-macro2", "regex", "reqwest", @@ -1521,6 +1522,25 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "is_executable" version = "0.1.2" @@ -1898,6 +1918,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16814a067484415fda653868c9be0ac5f2abd2ef5d951082a5f2fe1b3662944" +dependencies = [ + "is-wsl", + "pathdiff", +] + [[package]] name = "openssl" version = "0.10.45" @@ -1992,6 +2022,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 45539252c..9219db5ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ dioxus-html = { version = "0.3", features = ["hot-reload-context"] } dioxus-core = { version = "0.3", features = ["serialize"] } dioxus-autofmt = "0.3.0" rsx-rosetta = { version = "0.3" } +open = "4.1.0" [[bin]] path = "src/main.rs" diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs index 9fe453c49..ee6284ac1 100644 --- a/src/cli/cfg.rs +++ b/src/cli/cfg.rs @@ -45,6 +45,11 @@ pub struct ConfigOptsServe { #[clap(default_value_t = 8080)] pub port: u16, + /// Open the app in the default browser [default: false] + #[clap(long)] + #[serde(default)] + pub open: bool, + /// Build a example [default: ""] #[clap(long)] pub example: Option, diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs index ce0dd743e..e3485c1f1 100644 --- a/src/cli/serve/mod.rs +++ b/src/cli/serve/mod.rs @@ -68,7 +68,7 @@ impl Serve { Serve::regen_dev_page(&crate_config)?; // start the develop server - server::startup(self.serve.port, crate_config.clone()).await?; + server::startup(self.serve.port, crate_config.clone(), self.serve.open).await?; Ok(()) } diff --git a/src/server/mod.rs b/src/server/mod.rs index 42622466b..6daf7e289 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -55,7 +55,7 @@ struct WsReloadState { update: broadcast::Sender<()>, } -pub async fn startup(port: u16, config: CrateConfig) -> Result<()> { +pub async fn startup(port: u16, config: CrateConfig, start_browser: bool) -> Result<()> { // ctrl-c shutdown checker let crate_config = config.clone(); let _ = ctrlc::set_handler(move || { @@ -64,10 +64,11 @@ pub async fn startup(port: u16, config: CrateConfig) -> Result<()> { }); let ip = get_ip().unwrap_or(String::from("0.0.0.0")); + if config.hot_reload { - startup_hot_reload(ip, port, config).await? + startup_hot_reload(ip, port, config, start_browser).await? } else { - startup_default(ip, port, config).await? + startup_default(ip, port, config, start_browser).await? } Ok(()) } @@ -129,7 +130,7 @@ pub async fn hot_reload_handler( } #[allow(unused_assignments)] -pub async fn startup_hot_reload(ip: String, port: u16, config: CrateConfig) -> Result<()> { +pub async fn startup_hot_reload(ip: String, port: u16, config: CrateConfig, start_browser: bool) -> Result<()> { let first_build_result = crate::builder::build(&config, false)?; log::info!("🚀 Starting development server..."); @@ -319,14 +320,25 @@ pub async fn startup_hot_reload(ip: String, port: u16, config: CrateConfig) -> R .layer(Extension(ws_reload_state)) .layer(Extension(hot_reload_state)); - axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) - .serve(router.into_make_service()) - .await?; + let addr = format!("0.0.0.0:{}", port).parse().unwrap(); + + let server = axum::Server::bind(&addr).serve(router.into_make_service()); + + if start_browser { + let _ = open::that(format!("http://{}", addr)); + } + + server.await?; Ok(()) } -pub async fn startup_default(ip: String, port: u16, config: CrateConfig) -> Result<()> { +pub async fn startup_default( + ip: String, + port: u16, + config: CrateConfig, + start_browser: bool, +) -> Result<()> { let first_build_result = crate::builder::build(&config, false)?; log::info!("🚀 Starting development server..."); @@ -461,9 +473,14 @@ pub async fn startup_default(ip: String, port: u16, config: CrateConfig) -> Resu ) .layer(Extension(ws_reload_state)); - axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap()) - .serve(router.into_make_service()) - .await?; + let addr = format!("0.0.0.0:{}", port).parse().unwrap(); + let server = axum::Server::bind(&addr).serve(router.into_make_service()); + + if start_browser { + let _ = open::that(format!("http://{}", addr)); + } + + server.await?; Ok(()) } From 35dcacb9562569434cc5e6f95cefbb95904d26da Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 30 Apr 2023 16:35:11 -0500 Subject: [PATCH 485/895] use ascii64 encoding --- packages/server/Cargo.toml | 1 + .../src/props_html/deserialize_props.rs | 13 ++------ packages/server/src/props_html/mod.rs | 31 ------------------- .../server/src/props_html/serialize_props.rs | 12 ++----- 4 files changed, 7 insertions(+), 50 deletions(-) diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index b6293993c..753d4c2cb 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -47,6 +47,7 @@ tokio-stream = { version = "0.1.12", features = ["sync"], optional = true } futures-util = { version = "0.3.28", optional = true } postcard = { version = "1.0.4", features = ["use-std"] } yazi = "0.1.5" +base64 = "0.21.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] dioxus-hot-reload = { path = "../hot-reload" } diff --git a/packages/server/src/props_html/deserialize_props.rs b/packages/server/src/props_html/deserialize_props.rs index 64f2181ab..dcaa19905 100644 --- a/packages/server/src/props_html/deserialize_props.rs +++ b/packages/server/src/props_html/deserialize_props.rs @@ -1,18 +1,11 @@ use serde::de::DeserializeOwned; -use super::u16_from_char; +use base64::engine::general_purpose::STANDARD; +use base64::Engine; #[allow(unused)] pub(crate) fn serde_from_string(string: &str) -> Option { - let decompressed = string - .chars() - .flat_map(|c| { - let u = u16_from_char(c); - let u1 = (u >> 8) as u8; - let u2 = (u & 0xFF) as u8; - [u1, u2].into_iter() - }) - .collect::>(); + let decompressed = STANDARD.decode(string.as_bytes()).ok()?; let (decompressed, _) = yazi::decompress(&decompressed, yazi::Format::Zlib).unwrap(); postcard::from_bytes(&decompressed).ok() diff --git a/packages/server/src/props_html/mod.rs b/packages/server/src/props_html/mod.rs index 9e9b8721e..048e2aa90 100644 --- a/packages/server/src/props_html/mod.rs +++ b/packages/server/src/props_html/mod.rs @@ -52,34 +52,3 @@ fn serialized_and_deserializes() { } } } - -#[test] -fn encodes_and_decodes_bytes() { - for i in 0..(u16::MAX) { - let c = u16_to_char(i); - let i2 = u16_from_char(c); - assert_eq!(i, i2); - } -} - -#[allow(unused)] -pub(crate) fn u16_to_char(u: u16) -> char { - let u = u as u32; - let mapped = if u <= 0xD7FF { - u - } else { - 0xE000 + (u - 0xD7FF) - }; - char::from_u32(mapped).unwrap() -} - -#[allow(unused)] -pub(crate) fn u16_from_char(c: char) -> u16 { - let c = c as u32; - let mapped = if c <= 0xD7FF { - c - } else { - 0xD7FF + (c - 0xE000) - }; - mapped as u16 -} diff --git a/packages/server/src/props_html/serialize_props.rs b/packages/server/src/props_html/serialize_props.rs index f1282f07f..0012afb9c 100644 --- a/packages/server/src/props_html/serialize_props.rs +++ b/packages/server/src/props_html/serialize_props.rs @@ -1,6 +1,7 @@ use serde::Serialize; -use super::u16_to_char; +use base64::engine::general_purpose::STANDARD; +use base64::Engine; #[allow(unused)] pub(crate) fn serde_to_writable( @@ -14,14 +15,7 @@ pub(crate) fn serde_to_writable( yazi::CompressionLevel::BestSize, ) .unwrap(); - for array in compressed.chunks(2) { - let w = if array.len() == 2 { - [array[0], array[1]] - } else { - [array[0], 0] - }; - write_to.write_char(u16_to_char((w[0] as u16) << 8 | (w[1] as u16)))?; - } + write_to.write_str(&STANDARD.encode(compressed)); Ok(()) } From 970d9937580e4c2f2e2c1d5ac982442714da17c9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 1 May 2023 11:27:19 -0500 Subject: [PATCH 486/895] attempt to reconnect to server after sever disconnects in debug mode --- .../server/examples/axum-router/src/main.rs | 3 +- packages/server/src/adapters/axum_adapter.rs | 43 +++++++++++++++---- packages/server/src/adapters/salvo_adapter.rs | 25 ++++++++++- packages/server/src/adapters/warp_adapter.rs | 33 +++++++++++--- packages/server/src/render.rs | 39 +++++++++++++++-- 5 files changed, 122 insertions(+), 21 deletions(-) diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 2afa4a481..3994eeb51 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -9,6 +9,7 @@ use dioxus::prelude::*; use dioxus_router::*; use dioxus_server::prelude::*; +use serde::{Deserialize, Serialize}; fn main() { #[cfg(feature = "web")] @@ -62,7 +63,7 @@ fn main() { } } -#[derive(Clone, Debug, Props, PartialEq)] +#[derive(Clone, Debug, Props, PartialEq, Serialize, Deserialize)] struct AppProps { route: Option, } diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 1b572c804..541094674 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -267,6 +267,7 @@ where .collect::>() .join("/"); let route = format!("/{}", route); + println!("Serving static asset at {}", route); if path.is_dir() { self = self.nest_service(&route, ServeDir::new(path)); } else { @@ -275,20 +276,43 @@ where } // Add server functions and render index.html - self.connect_hot_reload() - .register_server_fns(server_fn_route) - .route( - "/", - get(render_handler).with_state((cfg, SSRState::default())), - ) + self.route( + "/", + get(render_handler).with_state((cfg, SSRState::default())), + ) + .connect_hot_reload() + .register_server_fns(server_fn_route) } fn connect_hot_reload(self) -> Self { #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] { - self.route( - "/_dioxus/hot_reload", - get(hot_reload_handler).with_state(crate::hot_reload::HotReloadState::default()), + self.nest( + "/_dioxus", + Router::new() + .route( + "/hot_reload", + get(hot_reload_handler) + .with_state(crate::hot_reload::HotReloadState::default()), + ) + .route( + "/disconnect", + get(|ws: WebSocketUpgrade| async { + ws.on_failed_upgrade(|error| { + println!("failed to upgrade: {}", error); + todo!() + }) + .on_upgrade(|mut ws| async move { + use axum::extract::ws::Message; + let _ = ws.send(Message::Text("connected".into())).await; + loop { + if ws.recv().await.is_none() { + break; + } + } + }) + }), + ), ) } #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))] @@ -302,6 +326,7 @@ async fn render_handler( State((cfg, ssr_state)): State<(ServeConfig

, SSRState)>, request: Request, ) -> impl IntoResponse { + println!("Rendering"); let (parts, _) = request.into_parts(); let parts: Arc = Arc::new(parts.into()); let server_context = DioxusServerContext::new(parts); diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 6ed4c2b3e..3751211e4 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -261,7 +261,14 @@ impl DioxusRouterExt for Router { } fn connect_hot_reload(self) -> Self { - self.push(Router::with_path("/_dioxus/hot_reload").get(HotReloadHandler::default())) + let mut _dioxus_router = Router::with_path("_dioxus"); + _dioxus_router = _dioxus_router + .push(Router::with_path("hot_reload").handle(HotReloadHandler::default())); + #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] + { + _dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws)); + } + self.push(_dioxus_router) } } @@ -504,3 +511,19 @@ impl HotReloadHandler { .await } } + +#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] +#[handler] +async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::http::StatusError> { + use salvo::ws::WebSocketUpgrade; + WebSocketUpgrade::new() + .upgrade(req, res, |mut ws| async move { + let _ = dbg!(ws.send(salvo::ws::Message::text("connected")).await); + while let Some(msg) = ws.recv().await { + if msg.is_err() { + return; + }; + } + }) + .await +} diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 5e9d23562..3d41d76cf 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -360,7 +360,7 @@ pub fn connect_hot_reload() -> impl Filter impl Filter impl Filter); + impl Drop for DisconnectOnDrop { + fn drop(&mut self) { + let _ = self.0.take().unwrap().close(); + } + } + + let _ = websocket.send(Message::text("connected")).await; + let mut ws = DisconnectOnDrop(Some(websocket)); + + loop { + ws.0.as_mut().unwrap().next().await; + } + }) + }, + )) } } diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index e8f6a67ec..1d32e2acd 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -25,9 +25,7 @@ impl Default for SSRState { impl SSRState { /// Render the application to HTML. pub fn render(&self, cfg: &ServeConfig

) -> String { - let ServeConfig { - app, props, .. - } = cfg; + let ServeConfig { app, props, .. } = cfg; let mut vdom = VirtualDom::new_with_props(*app, props.clone()); @@ -55,6 +53,41 @@ impl SSRState { // serialize the props let _ = crate::props_html::serialize_props::encode_in_element(&cfg.props, &mut html); + #[cfg(all(debug_assertions, feature = "hot-reload"))] + { + let disconnect_js = r#"(function () { + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + const url = protocol + '//' + window.location.host + '/_dioxus/disconnect'; + const poll_interval = 1000; + const reload_upon_connect = () => { + console.log('Disconnected from server. Attempting to reconnect...'); + window.setTimeout( + () => { + // Try to reconnect to the websocket + const ws = new WebSocket(url); + ws.onopen = () => { + // If we reconnect, reload the page + window.location.reload(); + } + // Otherwise, try again in a second + reload_upon_connect(); + }, + poll_interval); + }; + + // on initial page load connect to the disconnect ws + const ws = new WebSocket(url); + ws.onopen = () => { + // if we disconnect, start polling + ws.onclose = reload_upon_connect; + }; +})()"#; + + html += r#""#; + } + html += &index.post_main; html From 126ed2f9b8cc44fecf9516cd4525f6a744ecfc57 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 1 May 2023 11:28:20 -0500 Subject: [PATCH 487/895] remove log --- packages/server/src/adapters/axum_adapter.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index 541094674..f4b05e199 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -326,7 +326,6 @@ async fn render_handler( State((cfg, ssr_state)): State<(ServeConfig

, SSRState)>, request: Request, ) -> impl IntoResponse { - println!("Rendering"); let (parts, _) = request.into_parts(); let parts: Arc = Arc::new(parts.into()); let server_context = DioxusServerContext::new(parts); From a78ee4ffe77ad68a2b6e677446853bef3b086584 Mon Sep 17 00:00:00 2001 From: stephenandary Date: Mon, 1 May 2023 14:12:08 -0400 Subject: [PATCH 488/895] WIP - Update devcontainer to use debian bookworm --- .devcontainer/Dockerfile | 9 +++++++++ .devcontainer/devcontainer.json | 15 ++++++++++++--- .../linux/devcontainer-feature.json | 4 ---- .devcontainer/local-features/linux/install.sh | 6 ------ 4 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/local-features/linux/devcontainer-feature.json delete mode 100644 .devcontainer/local-features/linux/install.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..b20e962b9 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +# [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye +ARG VARIANT="slim-bookworm" +FROM rust:${VARIANT} +ENV DEBIAN_FRONTEND noninteractive +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive + +RUN apt-get -qq install build-essential libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1c5278332..aa536ab53 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,18 @@ { "name": "dioxus", - "image": "mcr.microsoft.com/devcontainers/rust:latest", + "remoteUser": "vscode", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, "features": { - "ghcr.io/devcontainers/features/common-utils:2": {}, - "./local-features/linux": {} + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": "true", + "username": "vscode", + "uid": "1000", + "gid": "1000", + "upgradePackages": "true" + } }, "containerEnv": { "RUST_LOG": "INFO" diff --git a/.devcontainer/local-features/linux/devcontainer-feature.json b/.devcontainer/local-features/linux/devcontainer-feature.json deleted file mode 100644 index daba5bc1f..000000000 --- a/.devcontainer/local-features/linux/devcontainer-feature.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "id": "linux", - "version": "0.0.1" -} \ No newline at end of file diff --git a/.devcontainer/local-features/linux/install.sh b/.devcontainer/local-features/linux/install.sh deleted file mode 100644 index 8f9ad5e1a..000000000 --- a/.devcontainer/local-features/linux/install.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -echo "Update Apt Database" -sudo apt-get update - -echo "Install Webkit Dependencies" -sudo apt-get -qq install build-essential libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev From 856650eb4d4c898af323fa4750e0a1bf2db9ac6a Mon Sep 17 00:00:00 2001 From: stephenandary Date: Mon, 1 May 2023 14:25:54 -0400 Subject: [PATCH 489/895] WIP - Add README --- .devcontainer/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .devcontainer/README.md diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000..74dbbe8c5 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,26 @@ +# Dev Container + +A dev container in the most simple context allows one to create a consistent development environment within a docker container that can easily be opened locally or remotely via codespaces such that contributors don't need to install anything to contribute. + +## Useful Links + +- +- +- +- + +## Using A Dev Container + +### Locally + +To use this dev container locally, make sure Docker is installed and in VSCode install the `ms-vscode-remote.remote-containers` extension. Then from the root of Dioxus you can type `Ctrl + Shift + P`, then choose `Dev Containers: Rebuild and Reopen in Devcontainer`. + +### Codespaces + +TBD + +## Troubleshooting + +If having difficulty commiting with github, and you use ssh or gpg keys, you may need to ensure that the keys are being shared properly between your host and VSCode. + +Though VSCode does a pretty good job sharing credentials between host and devcontainer, to save some time you can always just reopen the container locally to commit with `Ctrl + Shift + P`, then choose `Dev Containers: Reopen Folder Locally` From e68c806f8ce294cc855c116db3a2ba0d26cc6bd3 Mon Sep 17 00:00:00 2001 From: stephenandary Date: Mon, 1 May 2023 14:27:47 -0400 Subject: [PATCH 490/895] WIP - Update Readme Codespaces section with setup link --- .devcontainer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 74dbbe8c5..570435663 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -17,7 +17,7 @@ To use this dev container locally, make sure Docker is installed and in VSCode i ### Codespaces -TBD +[Codespaces Setup](https://docs.github.com/en/codespaces/developing-in-codespaces/creating-a-codespace-for-a-repository#creating-a-codespace-for-a-repository) ## Troubleshooting From 5f3c3d3f04217fcd1d58b5a182ee19dfba369037 Mon Sep 17 00:00:00 2001 From: stephenandary Date: Mon, 1 May 2023 14:49:38 -0400 Subject: [PATCH 491/895] WIP - Update base image to nightly so format on save works --- .devcontainer/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b20e962b9..c0e58fab8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ # [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye -ARG VARIANT="slim-bookworm" -FROM rust:${VARIANT} +ARG VARIANT="nightly-bookworm-slim" +FROM rustlang/rust:${VARIANT} ENV DEBIAN_FRONTEND noninteractive RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections From d3cf9f728c6d501944c143baa1e39d77ac9b0f45 Mon Sep 17 00:00:00 2001 From: stephenandary Date: Mon, 1 May 2023 14:54:21 -0400 Subject: [PATCH 492/895] WIP - remove comment in Dockerfile --- .devcontainer/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c0e58fab8..e2fd03ad8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,3 @@ -# [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye ARG VARIANT="nightly-bookworm-slim" FROM rustlang/rust:${VARIANT} ENV DEBIAN_FRONTEND noninteractive From 064bee4a9ff3d481622e56ed1e6da5a391020fa7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 1 May 2023 17:34:30 -0500 Subject: [PATCH 493/895] spawn hot reloading in a seperate thread --- .../examples/axum-hello-world/Cargo.toml | 8 +----- .../examples/axum-hello-world/src/main.rs | 15 ++++++++++- .../server/examples/axum-router/Cargo.toml | 8 +----- .../server/examples/axum-router/src/main.rs | 13 +++++++++ .../examples/salvo-hello-world/Cargo.toml | 8 +----- .../examples/salvo-hello-world/src/main.rs | 13 +++++++++ .../examples/warp-hello-world/Cargo.toml | 8 +----- .../examples/warp-hello-world/src/main.rs | 15 ++++++++++- packages/server/src/adapters/axum_adapter.rs | 18 +++++-------- packages/server/src/adapters/salvo_adapter.rs | 15 +++++------ packages/server/src/adapters/warp_adapter.rs | 27 ++++++++++--------- packages/server/src/hot_reload.rs | 15 +++++++++++ packages/server/src/render.rs | 8 +++--- 13 files changed, 106 insertions(+), 65 deletions(-) diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index b2c14561d..27c6af08b 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } axum = { version = "0.6.12", optional = true } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" +execute = "0.2.12" [features] default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index 6b6f32db7..3db117c02 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + PostServerData::register().unwrap(); GetServerData::register().unwrap(); tokio::runtime::Runtime::new() @@ -65,7 +78,7 @@ fn app(cx: Scope) -> Element { } } }, - "Run a server function" + "Run a server function! testing1234" } "Server said: {text}" }) diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml index 3e137d8f6..2ba621c9c 100644 --- a/packages/server/examples/axum-router/Cargo.toml +++ b/packages/server/examples/axum-router/Cargo.toml @@ -16,15 +16,9 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" tower-http = { version = "0.4.0", features = ["fs"], optional = true } http = { version = "0.2.9", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum", "tower-http", "http"] web = ["dioxus-web", "dioxus-router/web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 3994eeb51..0b5e55e4f 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -20,6 +20,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + use axum::extract::State; PostServerData::register().unwrap(); GetServerData::register().unwrap(); diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 9146ce3e2..50c92f237 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" salvo = { version = "0.37.9", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["salvo", "tokio", "dioxus-server/salvo"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index ff1081077..25ebbbff9 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + use salvo::prelude::*; PostServerData::register().unwrap(); GetServerData::register().unwrap(); diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index e182494b0..2c5d175ae 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" warp = { version = "0.3.3", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["warp", "tokio", "dioxus-server/warp"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 04684f803..3bbb95227 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + PostServerData::register().unwrap(); GetServerData::register().unwrap(); tokio::runtime::Runtime::new() @@ -45,7 +58,7 @@ fn app(cx: Scope) -> Element { cx.render(rsx! { h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count += 10, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| { diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index f4b05e199..6ca82b1e5 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -290,11 +290,7 @@ where self.nest( "/_dioxus", Router::new() - .route( - "/hot_reload", - get(hot_reload_handler) - .with_state(crate::hot_reload::HotReloadState::default()), - ) + .route("/hot_reload", get(hot_reload_handler)) .route( "/disconnect", get(|ws: WebSocketUpgrade| async { @@ -420,14 +416,13 @@ fn report_err(e: E) -> Response { /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] -pub async fn hot_reload_handler( - ws: WebSocketUpgrade, - State(state): State, -) -> impl IntoResponse { +pub async fn hot_reload_handler(ws: WebSocketUpgrade) -> impl IntoResponse { use axum::extract::ws::Message; use futures_util::StreamExt; - ws.on_upgrade(|mut socket| async move { + let state = crate::hot_reload::spawn_hot_reload().await; + + ws.on_upgrade(move |mut socket| async move { println!("🔥 Hot Reload WebSocket connected"); { // update any rsx calls that changed before the websocket connected. @@ -448,7 +443,8 @@ pub async fn hot_reload_handler( println!("finished"); } - let mut rx = tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + let mut rx = + tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver.clone()); while let Some(change) = rx.next().await { if let Some(template) = change { let template = { serde_json::to_string(&template).unwrap() }; diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 3751211e4..75387d1f9 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -455,9 +455,7 @@ impl HotReloadHandler { /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[derive(Default)] -pub struct HotReloadHandler { - state: crate::hot_reload::HotReloadState, -} +pub struct HotReloadHandler; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[handler] @@ -471,10 +469,10 @@ impl HotReloadHandler { use salvo::ws::Message; use salvo::ws::WebSocketUpgrade; - let state = self.state.clone(); + let state = crate::hot_reload::spawn_hot_reload().await; WebSocketUpgrade::new() - .upgrade(req, res, |mut websocket| async move { + .upgrade(req, res, move |mut websocket| async move { use futures_util::StreamExt; println!("🔥 Hot Reload WebSocket connected"); @@ -497,8 +495,9 @@ impl HotReloadHandler { println!("finished"); } - let mut rx = - tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + let mut rx = tokio_stream::wrappers::WatchStream::from_changes( + state.message_receiver.clone(), + ); while let Some(change) = rx.next().await { if let Some(template) = change { let template = { serde_json::to_string(&template).unwrap() }; @@ -518,7 +517,7 @@ async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::h use salvo::ws::WebSocketUpgrade; WebSocketUpgrade::new() .upgrade(req, res, |mut ws| async move { - let _ = dbg!(ws.send(salvo::ws::Message::text("connected")).await); + let _ = ws.send(salvo::ws::Message::text("connected")).await; while let Some(msg) = ws.recv().await { if msg.is_err() { return; diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 3d41d76cf..9a4ec7af4 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -372,12 +372,10 @@ pub fn connect_hot_reload() -> impl Filter impl Filter impl Filter); @@ -432,10 +433,12 @@ pub fn connect_hot_reload() -> impl Filter = tokio::sync::OnceCell::const_new(); +pub(crate) async fn spawn_hot_reload() -> &'static HotReloadState { + HOT_RELOAD_STATE + .get_or_init(|| async { + println!("spinning up hot reloading"); + let r = tokio::task::spawn_blocking(HotReloadState::default) + .await + .unwrap(); + println!("hot reloading ready"); + r + }) + .await +} diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 1d32e2acd..a05a63801 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -55,6 +55,7 @@ impl SSRState { #[cfg(all(debug_assertions, feature = "hot-reload"))] { + // In debug mode, we need to add a script to the page that will reload the page if the websocket disconnects to make full recompile hot reloads work let disconnect_js = r#"(function () { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const url = protocol + '//' + window.location.host + '/_dioxus/disconnect'; @@ -77,10 +78,9 @@ impl SSRState { // on initial page load connect to the disconnect ws const ws = new WebSocket(url); - ws.onopen = () => { - // if we disconnect, start polling - ws.onclose = reload_upon_connect; - }; + // if we disconnect, start polling + ws.onmessage = (m) => {console.log(m)}; + ws.onclose = reload_upon_connect; })()"#; html += r#" + + + + + + + + + + + + + + +

+ +
+ +
+ + + + + + + + +
+
+

Document not found (404)

+

This URL is invalid, sorry. Please use the navigation bar or search to continue.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/FontAwesome/css/font-awesome.css b/docs/nightly/guide/en/FontAwesome/css/font-awesome.css new file mode 100644 index 000000000..540440ce8 --- /dev/null +++ b/docs/nightly/guide/en/FontAwesome/css/font-awesome.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/docs/nightly/guide/en/FontAwesome/fonts/FontAwesome.ttf b/docs/nightly/guide/en/FontAwesome/fonts/FontAwesome.ttf new file mode 100644 index 0000000000000000000000000000000000000000..35acda2fa1196aad98c2adf4378a7611dd713aa3 GIT binary patch literal 165548 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 z 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 d0mW2@EHO9NV8h3u2x_sp}KECIB>@9+Qn{FBV{ zJTr4<=FH5QnRCvZnOu5{#2&j@Vw_3r#2?PKa|-F4dtx{Ptp0P(#$Rn88poKQO<|X@ zOW8U$o^4<&*p=|D!J9EVI}`7V*m|~_En`<8B*M-{$Q6LOSfmND1Z!lia3ffVHQ_mu zwE*t)c_Na~v9UCh+1x2p=FeL7+|;L;bTeUAHg(eEDN-*};9m=WXwJOhO^lgVEPBX5Gh_bo8QSSFY{vM^4hsD-mzHX!X?>-tpg$&tfe27?V1mUAbb} z1dVewCjIN7C5$=lXROG% zX4%HIa)VTc_%^_YE?u@}#b58a4S8RL@|2s`UUucWZ{P9NJxp5Fi!#@Xx+(mZ+kdt3 zobw#*|6)Z(BxCGw^Gi+ncRvs|a|3xz=tRA9@HDV~1eqD)`^`KTPEg`UdXhq18})-@}JTHp30^)`L{?* z;c)alkYAc@67|W!7RDPu6Tsy@xJCK8{2T9-fJw6?@=A(w^}KCVjwlOd=JTO=3Zr+< zIdd?1zo-M^76}Jf!cpLfH`+2q=}d5id5XLcPw#xVocH5RVG7;@@%R>Sxpy8{(H9JH zY1V)?J1-AIeIxKhoG1%;AWq7C50ok3DSe?!Gatbry_zpS*VoS6`$~lK9E?(!mcrm1 z^cLZ1fmx5Ds`-ethCvMtDTz zMd=G1)gR$jic|1SaTLaL-{ePJOFkUs%j634IMp}dnR5yGMtsXmA$+JDyxRuSq*)bk zt3tSN2(J<@ooh3|!(R%VsE#5%U{m-mB7fcy&h(8kC(#>yA(JCmQ6|O1<=_U=0+$AY zC)@~M`UboR6Xm2?$e8Z$r#u8)TEP0~`viw@@+){#874R?kHRP|IU4&!?+9Cy52v^I zPV4Xd{9yc;)#l?0VS#6g@ z`#y))03Laq@^6Z#Z*uvzpl{$JzFJgn&xHlNBS|Eb!E@}~Z$^m!a9k34KX zT|VETZ;B_E$Ai8J#t5#kATCAUlqbr&P~-s)k^FfWyz}iK@`B$FI6L0u1uz5fgfqgU zRBmB>F8s_qp1HWm1!aXOEbpf`U?X|>{F`8Md500U3i;Mh9Kvbd(CeuC>077ww4g^h zKgM(A48W`XEDE~N*Th^NqP#S7&^w2Vpq+df2#@A*&4u~I+>t)9&GYcop9OtUo=;2d zGSq?IMBAYZffMC1v^|Z|AWdQ38UdJS4(H(nFI<|%=>0iAn3lvcSjIR(^7r7QuQI0a zm+@Z9QXmf!efG1**%Ryq_G-AQs-mi^*WO#v+tE9_cWLjXz1Q{L-uqzh z-Vb`UBlaT|M;ecG9GQJ&>5)s1TzBO5BM%;V{K#`h4juXPkq?e&N9{)|j&>ZKeRS#3 zOOIZ6^!B3<9)0}ib4L#y{qxZe{ss8}C5PC)Atkb2XK%PS)jPMht9Na0x_5hTckhAT zOz+FRJ-xk0*b(QE(2)^GQb*<<={mCZNczb3Bi%<19LXGc`AE-^-lOcO^Jw^J>ge2~ zT}Rg*O&{HUwEO6RqnV>GAMK$M`~TX%q<>-my#5LOBmex)pWgq|V@{jX>a;k`PLtE< zG&ohK;*_0|<6n-C93MK4I*vGc9shKE;CSEhp5tA|KOBE|yyJM=@i)g?jyD~Db^OKg zhNH*vXUCr$uRH$ec+K$#$E%LtJ6>`8&T-iBTicKH)SNMZS zB8UG!{1{Y=QL&oLMgLzR(}0Y>sN0TqgG|kLqv_VcVSLD)aJ?AC^D!bLa6K5Ut1)YA zghRXq;YBrYhrzOK23vXorq6v~v*CBb?*bYw$l-3J@cY5H}8Gr;t8{e8!J}L*5e>!hOQnM3g=8eoXDiYZBlmBW?=(Qvo;ib;hP4-|5>J zo6*MD%*UW90?aI=ncV;fJZB$fY|a73<^rd=!0(I%TsLE9TH#hRHV<&~b~82~@n<2= z1-*oTQL{zWh}4H zGjX>}SbW{R;(k^VBouiebp<&Q9S1P`GIlM(uLaz7TNt~37h`FJ-B1j-jj@}iF}B$Yhy1^cv|oM`3X|20-GXwq z0QapK#%@FUZ9ik|D}cWpad#li_7EK6?wrrq4l5kOc5H@2*p5ENc6Pxb%`OEl1=q{i zU1`Sdjxcu562^8fWbEEDi1(A=o?`5)DC_=i#vVX^45ZpSrpE35`g>WA+_QYDo!1%Byk?;4A*Y^%H_McC{^)mJp(mf6Mr$1rr8Klp< z@9$&m+0Bd{OfmMH!q^XxU*>tneq@E)#@LU6-}5Nz`DYpXi4*QA#$MRP*w045^)U8x zl=XAu_Y36n%QPIqUi^r$mjH7JWgdEmv0oiv>}BNj>jtO;GSSiGr=LO--M;f3$4%-kcdA5=kp1;?w1)iU%_3WyqWQmjf@AcVZ3xc<7I~# zFHgbYU4b-}3LN4>NEZft6=17@TlH$jBZ!NjjQC2%Yu;hJu9NWwZ@DynQp=tBj8Wjw$e9<5A{>pD{iW zZqogXPX_!HxT$LypN98z;4>ox_a@^r4>R7`&G@Wh#%HG(p9^;e{AczsK5r7^^FxfE z1>DZ=f&=UVl(8@Y2be_)+!n?cUjPUAC8+bcuQI+Aab3F@Uxu=lJpt$oQq38DE=X{7U3=m6P!eKVy6&>UK5q-?WYKFCon} zcwbuv_Xy+HBi;48;XYwJy_)eGknfFvzbOHS_{~WFRt)zJ zijpU?=0x zkwe%IkXL3J<39wBKYX6?A1iQgGX8uw<3E|t_zN{~?=k)}E8{7uHGX6%I@xLJ5o5hU3g}A@9GyXR4dV3$^??m7ZGyeD0jQ;~={sZ6d0>}3fa8JQ~ z#Q6Kj>z^jLM;Px_;9g|>2lp6?Oy32JW8UD|ZH#LugXW9=mzl&9Ov2uUBsVZgS;-{zFeKKwOfnbOFe$i&Nu~HMe}YLB^Wk1(Qs^2cg^_pF zV@!&4GARo9*fb`^0bBDClWMmysSaUvuQREB7n2(BZbV*M)y$0@8CXG!nX&m5FyO}f|^_bYrq)EtQ3jEW$ z;E;a$iwt`}|2xOlf`@fNIFLzjYz@1@vMcQB;TbKpR_b1>hK{W@uw#sVI6JqW86H;C ztQ;P%k-Nf8ey^cATop^SG>2V0mP~Z;=5SL5H#}UQ-NIABSS;9=rYBEjx70^!0%|%? z6H%vBBRb1si5UK{xwWyrI#6mdl~NhlB{DFSQ4f#HYnQ4Tr9_9++!S!BCwdbtt-PhV z2|9^MD=%7f(aK494ZCcz4t6dY`X;_62ywrIPovV+sT0pH?+{mwxjh%^> zh_?T`uiv2^KX}>z4HVY!Y%V1QDcBvi>!sD@MEbj99(bg@lcBxTD9~gYzfIm>7jFFl;^hEgOD8Clhu+6jw>0z&OhJ=2DoJ42R3QaA zWOOLCseE6;o!xG!?ra~f^>o~D+1yBE?qxT0^k{Eo?@YU;MW)Dk7u-Ja^-t=jry`Nm z^!iU;|I=I9eR|&CLf`eUDtM5Q2iZ}-MO8dOpsgMv)7Ge`r77T1(I!FduCuw%>+xyh zv~lQApLDjitE7#8{D!C9^9KL8O}^S6)E?BVMw_qP`rdoia-YG@KjOf%Qh4Bnt8Mcoi9h#JRYY3kEvn*UVbReO50BrmV+ z;MZw4c4)uX7XS38vL%mZ(`R5ww4GL|?R_+gqd5vmpyBRdmy(bdo1(0=sB8@yxdn)~lxbJjigu9=)pPhNBHJ@OCr@Hfy7 zMKpelG=3bck_~6$*c^5qw$ra?cd)OqZ$smlOvLJWm7$z_{bM*t_;dW+m52!n&yhSI z0)LYKbKpO(yrBb!r(;1ei=F17uvjq5XquDp?1L{4s1~Hu@I46id3j>UeJTcx0fQ!$ z&o9RBJJn}4D52n3P@|_Z2y%SzQ!WJ22E$LC;WNiX*{T?@;Pj!}DC|#~nZ>-HpIS<2 za>P22_kUiz%sLYqOLTT7B=H>lmeZ$;kr+*xoe54)>BRz1U!muO7@@$$G=552gn*!9 zJ(lYeq-%(OX#D?e|IqRz)>flsYTDXrc#58b-%`5Jmp#FEV%&+o&w?z>k%vUF^x&@! zd}aqf<-yN_(1OoX0~BNi5+XV}sW1Mo_rky5sw&#MPqeg*Iv+ow^-qi|g!>=1)d@|( zIJ=tJ4Yw%YfhiFbenxIIR1N1mmKeveFq!eFI?k+2%4<3`YlV3hM zS45R<;g^uVtW5iZbSGet@1^}8sBUEktA@_c>)?i}IE-EQTR@N-j%b9$Syc1{S3U?8e~d3B1?Lij0H27USiF&gR}A>wG-vBGIPuh*4ry;{Khxekv}wCTm%_>vhFZSJ)Pw2iv6Q4YVoQ`J2w?yCkiavVTWeVa)j|q=T9@J0pTtcQX!VHnIM6Al- z^*7Og!1y$xN4)5fYK&2X5x-Om4A;1k20|=O+$wl^1T}IRHkcq<^P$a{C0fAii(ypB z{ef1n(U1a&g|>5}zY?N{!tOqN_uYr3yPejjJ>KeR7IW!#ztw(g!*Hj~SpH|bkC%t5kd^Q2w*f{D8tJPwQ z++kT&2yEHVY_jXXBg!P7SUbSC;y1@rj$sqoMWF2=y$%ua1S%Nn_dvGwR*;O^!Fd?1 z8#WkKL1{>+GcdW?sX2^RC#k8D;~{~1M4#fpPxGDbOWPf?oRS^(Y!}arFj}-9Ta5B$ zZhP0#34P$Fx`;w}a*AU%t?#oPQ+U$umO}+(WIxS!wnBcQuM;%yiYhbKnNwXa7LiRjmf+(2(ZG}wiz%sgWJi>jgGIsPnZ=KfX?8mJ2^L!4-hBx#UR zZa((80+3k2t!n9h@La(dm&Qrs_teRTeB}Y= zShqm6zJdPGS+juA6^_Mu3_1sz1Hvx#*|M6pnqz`jk<&F@Wt;g%i&gunm7lM5)wE@q zvbn6Q=6IU;C_@UMWs|fmylAcBqr(MowarQT7@9BsXzyH534G z1e0`Rlnqb_RAIW{M7dQoxdg$ z;&VZRA?1jrgF9nN0lg?)7VU>c#YI}iVKVtMV&I^SUL2sA9Xn2<8mY@_)qZF;^OV!$ z;QVMjZTMUtC^eDXuo)DkX75sJ*#d6g{w?U1!Fbwid(nlSiF_z zStRqVrV`8MJBg{|ZM^Kzrps2`fI(Eq&qUZ%VCjWLQn)GthGkFz0LcT(tUy)_i~PWb ze1obC@Hu0-n}r4LO@8%lp3+uoAMDWnx#|WFhG&pQo@eXSCzjp(&Xl4$kfY60LiIx^ zs+SA=sm(K<-^V>WxOdf!NXC0qN&86q?xh#r;L)>)B|KXvOuO+4*98HO?4jfcxpk`^ zU^8+npM|PWn*7Nj9O_U%@pt)^gcu2m|17^}h}J6KWCJ>t zv@Qsc2z0711@V0%PDVqW?i)a)=GC>nC+Kx~*FeS}p5iNes=&dpY_lv9^<|K`GOJMG zE5^7&yqgjFK*qz6I-su3QFo4`PbRSbk|gNIa3+>jPUVH}5I6C)+!U&5lUe4HyYIe4 z>&a$lqL(n;XP)9F?USc6ZA6!;oE+i8ksYGTfe8;xbPFg9e&VVdrRpkO9Zch#cxJH7 z%@Bt~=_%2;shO9|R5K-|zrSznwM%ZBp3!<;&S0$4H~PJ&S3PrGtf}StbLZKDF_le= z9k)|^Do10}k~3$n&#EP*_H_-3h8^ZuQ2JXaU@zY|dW@$oQAY%Z@s0V8+F~YQ=#aqp z=je#~nV5}oI1J`wLIQ^&`Mj01oDZ;O`V>BvWCRJd%56g!((T@-{aY6fa;a0Vs+v@O z0IK2dXum&DKB?-ese^F~xB8#t6TFirdTy3(-MedKc;2cI&D}ztv4^I%ThCj* ziyQ90UpuyI`FYm%sUlWqP(!Qcg-7n%dk-&uY15{cw0HD+gbuz}CQP*u8*(+KCYFiz80m1pT=kmx0(q(xrCPMsUH1k{mefDSp) zD5G^q?m1N%Jbl&_iz65-uBs{~7YjNpQ%+H^=H7i%nHnwimHSGDPZ(Z;cWG1wcZw|v z%*juq&!(bo!`O7T>Wkon^QZ-rLvkd_^z#)5Hg zxufObryg!`lzZc#{xRRv6592P5fce0Hl-xEm^*nBcP$v z0`KR64y6=xK{a*oNxW9jv+9)$I9SxN-Oig_c%UK7hZDj_WEb$BDlO#*M?@b>eU7 zxN!%UE+w#Wg$bqFfc# zeDOpwnoY)%(93rx(=q9nQKg6?XKJZrRP#oo(u>h_l6NOMld)_IF( zs6M+iRmTC+ALc}C7V>JEuRjk9o)*YO8Y}oKQNl2t?D;qFLv4U`StSyoFzFYuq>i@C zEa1!N?B0BK0gjTwsL04McVmu=$6B!!-4bi1u_j7ZpCQm-l2u7AlYMmx zH!4a*@eEhENs{b-gUMy{c*AjMjcwAWGv@lW4YQtoQvvf*jQ2wL8+EGF4rQjAc;uiEzG%4uf z9wX{X3(U5*s$>6M z)n+q=_&#l6nEa|4ez8YOb9q{(?8h1|AYN<53x+g()8?U_N+)sEV;tdoV{pJ^DTD)ZvO|;^t&(V6L2z~TSiWu zI&#bLG#NGMHVY^mJXXH_jBGA?Np1q;)EYzS3U=1VKn3aXyU}xGihu`L8($R|e#HpJ zzo`QozgXO&25>bM*l>oHk|GV&2I+U-2>)u7C$^yP7gAuth~}8}eO^2>X_8+G@2GX0 zUG8;wZgm*=I4#ww{Ufg2!~-Uu*`{`!$+eE)in1}WPMJ%i|32CjmFLR8);bg^+jrF* zW0A!Zuas6whwVl!G+Vp(ysAHq9%glv8)6>Sr8w=pzPe1s`fRb9oO^yGOQW^-OZ=5? zNNaJk+iSAxa}{PtjC&tu_+{8J_cw=JiFhMqFC!}FHB@j}@Q$b&*h-^U)Y&U$fDWad zC!K&D&RZgww6M(~`@DA92;#vDM1_`->Ss*g8*57^PdIP-=;>u#;wD4g#4|T7ZytTY zx(Q8lO+5Ris0v-@GZXC@|&A*DPrZ51ZeSyziwc>%X>dNyCAL zOSDTJAwK7d2@UOGmtsjCPM9{#I9Gbb7#z25{*;Tyl-Zho(Oh~-u(5CLQl;2ot%#Nl z_cf{VEA=LuSylKv$-{%A=U+QBv0&8bP;vDOcU|zc3n!Nu{9=5j6^6DL&6tm-J4|~) z9#1w(@m3N|G3n9Xf)O<|NO+P)+F(TgqN3E#F8`eIrDZn0=@MQ%cDBb8e*D_eBUXH+ zOtn|s5j9y2W~uaQm*j{3fV=j|wxar?@^xjmPHKMYy0eTPkG*<=QA$Wf)g`tfRlZ0v ztEyRwH(8<%&+zbQ+pg>z^Ucf8Jj>x$N*h{buawh;61^S+&ZX>H^j?#nw!}!~35^Z# zqU|=INy-tBD+E^RCJdtvC_M2+Bx*2%C6nTfGS!1b*MJvhKZZPkBfkjIFf@kLBCdo) zszai4sxmBgklbZ>Iqddc=N%2_4$qxi==t>5E!Ll+-y(NJc+^l)uMgMZH+KM<|+cUS^t~AUy&z{UpW?AA~QO;;xntfuA^Rj7SU%j)& zVs~)K>u%=e(ooP|$In{9cdb}2l?KYZinZ8o+i;N-baM#CG$-JMDcX1$y9-L(TsuaT zfPY9MCb3xN8WGxNDB@4sjvZ10JTUS1Snvy5l9QPbZJ1#AG@_xCVXxndg&0Cz99x`Z zKvV%^1YbB2L)tU+ww(e6EZYzc6gI5g;!?*}TsL=hotb0Mow8kxW*HVdXfdVep4yL` zdfTcM*7nwv5)3M-)^@ASp~`(sR`IsMgXV>xPx0&5!lR8(L&vn@?_Oi2EXy)sj?Q8S$Mm zP{=PsbQ)rJtxy*+R9EqNek1fupF(7d1z|uHBZdEQMm`l!QnDTsJ_DX2E=_R?o*D5) z4}Rh2eEvVeTQ^UXfsDXgAf@6dtaXG>!t?(&-a~B^KF@z*dl$BLVOt|yVElz!`rm5n z&%<$O{7{?+>7|f%3ctTlD}Sc0Zs_hY;YO-&eOIT+Kh%FJdM|_@8b7qIL;aj#^MhF1 z(>x4_KPKYTl+AOj0Q$t3La4&;o`HP%m8bgb`*0vs83ZT@J#{j%7e8dKm;){k%rMw* zG9eKbw_mh1PHLUB$7VNcJ=oL;nV~#W;r|rv;ISD5+Q-FH5g~=&gD`RrnNm>lGJ1GE zw`K+PW!P*uxsEyAzhLvBOEUkj>)1sV6q-RhP*nGS(JD%Z$|wijTm)a5S+oj03MzBz zPjp$XjyM!3`cFtv`8wrA`EpL(8Soof9J(X7wr2l^Y-+>){TrmrhW&h}yVPonlai>; zrF!_zz4@5^8y@95z(7+GLY@+~o<>}!RDp|@N4vi4Y-r@AF@6Q7ET8d9j~&O$3l#Yuo`voKB12v8pK*p3sJO+k{- zak5sNppfOFju-S9tC#^&UI}&^S-3TB^fmi<0$e%==MK3AqBrn!K@ZCzuah-}pRZc{ z?&7p`mEU5_{>6x=RAFr4-F+FYOMN%GSL@mvX-UT3jRI;_TJH7}l*La_ztFn+GQ3;r zNk;eb?nh&>e?Z$I<$LDON!e1tJ26yLILq`~hFYrCA|rj2uGJHxzz@8b<} z&bETBnbLPG9E*iz!<03Ld4q;C140%fzRO5j*Ql#XY*C-ELCtp24zs*#$X0ZhlF~Qj zq$4Nq9U@=qSTzHghxD(IcI0@hO0e}l7_PKLX|J5jQe+67(8W~90a!?QdAYyLs6f^$ zgAUsZ6%aIOhqZ;;;WG@EpL1!Mxhc_XD!cTY%MEAnbR^8{!>s|QGte5Y=ivx6=T9Ei zP_M&x-e`XKwm+O(fpg~P{^7QV&DZPW)$j@GX#kClVjXN6u+n=I$K0{Y-O4?f;0vgV zY+%5cgK;dNK1}{#_x-Zyaw9sN`r9jST(^5&m&8IY?IBml#h0G3e?uSWfByzKHLe8) z9oCU{cfd~u97`w2ATe{wQPagk*)FX|S+YdySpplm-DSKB*|c>@nSp$=zj{v3WyAgw zqtk_K3c5J|0pC zSpww86>3JZSitYm_b*{%7cv?=elhCFy1v6m)^n?211803vG_;TRU3WPV`g7=>ywvsW6B76c-kXXYuS7~J+@Lc zSf%7^`HIJ4D|VX9{BlBG~IV;M->JId%#U?}jR@kQ&o5A3HyYDx}6Nc^pMjj0Jeun)M=&7-NLZ9@2 z)j60}@#z8oft^qhO`qgPG;Gf4Q@Zbq!Fx_DP1GkX<}_%EF`!5fg*xCsir}$yMH#85 zT3Y4bdV)bucC=X;w24>D>XjaA@K`En^++$6E!jmvauA$rc9F%b=P&f^I7M+{{--HM z0JXFl21+}*Oz8zr@T8JQp9Td0TZ7rr0+&rWePPKdaG}l-^)$@O*ON;2pkAjf4ZSg# zy{PLo>hhTUUK_q5L{o!vKb^7AIkbXB zm3BG{rbFE>fKfZsL4iKVYubQMO_AvYWH<3F_@;7*b}ss*4!r5a-5Mr{qoVbpXW1cja+YCd!nQ3xt*CEBq_FNhDc93rhj=>>F59=AN5 zoRmKmL))oDox0VF;gltwNSdcF9cb*OX3{Gx?X{Q-krC~b9}_3yG8Bn{`W6m}6YD#q zAkEzk)zB|ZA2Ao`dW^gC77j#kXk7>zOYg~2Y0NyG9@9L)X=yRL!=`tj7; z^S=K3l)dWTz%eniebMP!Z)q@7d(l_cR;2OvPv7I~Va{X>R@4XXh- zOMOMef=}m)U?`>^E`qUO(+Ng$xKwZ1|FQ|>X41&zvAf`(9 zj3GGCzGHqa8_lMGV+Q3A(d5seacFHJ92meB0vj+?SfQ~dL#3UE!1{}wjz|HPWCEHI zW{zYTeA(UwAEq6F%|@%!oD5ebM$D`kG45gkQ6COfjjk-==^@y6=Tp0-#~0px=I@H# z7Z|LQii;EBSfjse{lo}m?iuTG`$i6*F?L9m*kGMV_JUqsuT##HNJkrNL~cklwZK&3 zgesq4oycISoHuCg>Jo;0K(3&I(n-j7+uaf)NPK7+@p8+z!=r!xa45cmV`Mna1hT=i zAkgv-=xDHofR+dHn7FZvghtoxVqmi^U=Tk5i*(?UbiEGt9|mBN4tXfwT0b zIQSzTbod84Y<){2C!IJja=k65vqPM|!xFS?-HOK!3%&6=!T(Z$<>g6+rTpioPBf57 z$!8fVo=}&Z?KB-UB4$>vfxffiJ*^StPHhnl@7Fw@3-N|6BAyp|HhmV#(r=Ll2Y3af zNJ44J*!nZfs0Z5o%Qy|_7UzOtMt~9CA*sTy5=4c0Q9mP-JJ+p-7G&*PyD$6sj+4b>6a~%2eXf~A?KRzL4v_GQ!SRxsdZi`B(7Jx*fGf@DK z&P<|o9z*F!kX>I*;y78= z>JB#p1zld#NFeK3{?&UgU*1uzsxF7qYP34!>yr;jKktE5CNZ3N_W+965o=}3S?jx3 zv`#Wqn;l-4If#|AeD6_oY2Y||U?Fss}Sa>HvkP$9_KPcb_jB*Jc;M0XIE+qhbP$U2d z&;h?{>;H=Sp?W2>Uc{rF29ML>EiCy?fyim_mQtrgMA~^uv?&@WN@gUOPn(379I}U4Vg~Qo)jwJb7e_Pg^`Gmp+s5vF{tNzJVhBQ z$VB8M@`XJsXC!-){6wetDsTY94 G*yFsbY~cLNXLP73aA74Mq6M9f^&YV`isWW zU@CY~qxP|&bnWBDi{LM9r0!uDR`&3$@xh)p^>voF;SAaZi_ozepkmLV+&hGKrp0jy9{6cAs)nGCitl6Cw2c%Z0GVz1C zH-$3>en`tRh)Z(8))4y=esC5oyjkopd;K_uLM(K16Uoowyo4@9gTv5u=A_uBd0McB zG~8g=+O1_GWtp;w*7oD;g7xT0>D9KH`rx%cs^JH~P_@+@N5^&vZtAIXZ@TH+Rb$iX zv8(8dKV^46(Z&yFGFn4hNolFPVozn;+&27G?m@2LsJe7YgGEHj?!M`nn`S-w=q$Y4 zB>(63Fnnw_J_&IJT0ztZtSecc!QccI&<3XK0KsV4VV(j@25^A-xlh_$hgq6}Ke~GZ zhiQV3X|Mlv6UKb8uXL$*D>r^GD8;;u+Pi;zrDxZzjvWE#@cNGO`q~o7B+DH$I?5#T zf_t7@)B41BzjIgI68Bcci{s-$P8pU>=kLG8SB$x;c&X=_mE3UN@*eF+YgP|eXQVn) z)pd&9U^7r1QaaX{+Wb-9S8_jQZC19~W) z*_+RuH*MPD=B_m7we#2A@YwQv$kH2gA%qk7H)?k!jWbzcHWK497Ke<$ggzW+IYI2A zFQ_A$Ae4bxFvl4XPu2-7cn1vW-EWQ6?|>Qm*6uI!JNaRLXZFc5@3r48t0~)bwpU*5 z-KNE}N45AiuXh{&18l_quuV$6w|?c-PtzqcPhY)q{d+Hc_@OkartG`dddteZXK&Je zGpYJ-+PmEUR`sOnx42*X$6KT~@9ze#J>YvvaN24jI}4QG3M;w<>~!2i@r)9lI!6N1 z0GN((xJjHUB^|#9vJgy=07qv}Kw>zE+6qQns-L}JIqLFtY3pDu_$~YrZOO$WEpF>3 zXTu#w7J9w+@)x-6oW(5`w;GI8gk@*+!5ew8iD$g=DR*n@|2*R`zxe7azdr7~Z;$%< zSH@*lQ9U(Hx^%Fb|1?Smv({(NaZW+DGsnNWwX(DFUG8)(b6Rn>MzUxlZhNbVe>`mS zl&aJjk3F~9{lT-}y>e~pI}kOf@0^%Vdj&m(iK4LTf6kmF!_0HQ$`f-eBnmdTsf$_3 zR`hz2EjKIKWL6z@jj1}us>ZmY)iQInPifzSiOFN92j9$pX*CuV8SPrD#b%Qa97~TI zS6)?BPUgFnkqG8{{HUwd)%ZsvurI~=Jr8YSkhUA!RANJ;o|D->9S9QB5DxTybH&PGFtc0Z>dLwr|Ah}aX`XwTtE&UssYSEILtNijh)8)WWjMm$uT;+p1|=L z><4lEg%APBLn+FRr&2tGd)7icqrVXFE;+3j`3p~mvsiDMU>yK$19$B@8$Dy4GClfzo4)s_o2NuM3t-WhCrXE>LQ z_CQtR*!a0mhnw#I2S=WxT_H@^Saif`)uhLNJC zq4{bSCwYBd!4>6KGH5y~WZc@7_X~RqtaSN(`jfT!KhgGR)3iN50ecR$!|?Vq8|xa+ zY#*+B=>j4;wypclu7?wd+y06`GlVf2vBXzuPA;JgpfkIa1gXG88sZ*aS`(w z_9`LL4@aT0p!4H7sWP`mwUZRKCu@UWdNi-yebkfmNN+*QU+N*lf6BAJ$FNs^SLmDz z^algGcLq`f>-uKOd_Ws4y^1_2ucQaL>xyaQjy!eVD6OQi>km;_zvHS=ZpZZrw4)}Z zPz(rC?a`hZiQV9o^s>b?f-~ljm1*4IE<3plqCV}_shIiuQl=uKB4vUx2T$RCFr0{u z1v660Y3?>kX@{19i6;*CA}pJsFpo{nculW61+66XAOBZD< z{H|h`mJS5C2;ymL##}U*MC%fL0R97OSQ@lUXQ-j?i{z{=l-!$64H{LlTLo{Ln<|OV zBWq*5LP`KJl74fC{GzzP_Z;;;6i--QpZUrtHC@+RBlt+=_3TyV4gk=4b{TBJAx!GehYbTby(&-R337 zQ%g2)Uc&K|x|eL0yR*VCXDBqZ89C(obOFYYht(k`^q0OaQ*Y{)@7xE~KQ7XN)hGlZ zl5$1<#s!tyf%>mbIG(9WR`R*{Qc_h(ZGT^8>7lXOw^g1iIE2EdRaR^3nx_UUDy#W6 zy!q(v^QLL*42nxBK!$WVOv)I9Z4InlKtv#qJOzoZTxx86<5tQ*v528nxJ^sm+_tRp zT7oVNE7-NgcoqA#NPr*AT|8xEa)x&K#QaWEb{M34!cH-0Ro63!ec@APIJoOuP&|13 z9CFAVMAe@*(L6g{3h&p2m!K zEG?(A$c(3trJ5LHQ@(h3@`CB*ep}GDYSOwpgT=cZU;F&F6(b=V*TLLD z*fq(p>yRHTG1ttB*(Q8xLAl4cZdp^?6=QjcG;_V(q>MY0FOru|-SE}@^WElQTpCQZ zAMJy_$l;GISf1ZmbTzkD(^S!#q?(lDIA?SIrj2H$hs*|^{b|Kp!zXPTcjcCcfA+KN zdlV!rFo2RY@10$^a_d*-?j7HJC;KhfoB%@;*{;(hx_iP`#qI(?qa{b zH|YEvx~cE^RQ4J}dS>z%gK-XYm&uvZcgoyLClEhS(`FJ^zV!Vl&2c{U4N9z_|1($J znob`V2~>KDKA&dTi9YwyS#e-5dYkH?3rN(#;$}@K&5Yu}2s&MGF*w{xhbAzS@z(qi z&k99O!34}xTQ`?X!RRgjc)80Qud0{3UN4(nS5uZ1#K=^l&$CdhVr%4<67S=#uNP z$hnqV471K$Gy&){4ElZt?A?0NLoW2o_3R)!o~sw#>7&;Vq954STsM(+32Z#w^MksO zsrqpE@Js9$)|uQzKbXiMwttapenf8iB|j(wIa2-@GqE@(2P#M09Rvvhdu!sE0Mx&cK&$EtK}}WywYEC~MF5r3cUj%d$|lLwY4>`) z_D++uNojUl@4Cz8YF3nvwp>JWtwGtSG`nnfeNp(_RYv`S2?qhgb_(1$KD6ymTRgnD zx^~3GBD2+4vB9{=V_iMG*kQTX;ycG^`f{n+VxR4Ah!t~JQ6Z?Q;ws}Jw|#YE0jR0S z+36oq6_8xno^4J?Y02d!iad3xPm+8~r^*Vvr4A<|$^#UEbKvJ9YHF=Ch2jF`4!QS# zl8We8%)x>ejzT^IH%ymE#EBe2~-$}ZXtz&vZ_NgVk4kc zOv-dk(6ie2e{lAqYwn9Q$weL#^Nh?MpPUK z#Cb)4d96*6`>t7Zwsz#_qbv6CnswLS9Jt|b`8Mqz?`?H1tT99K#4#d+VwAy}#eC74 z;%UFxaNB!Zw`R9){Pncrny4>k;D}TV2BU0ua-+Fsp>wmcX#SGkn`h0O`pN*`jUj8q zIlnc7x6NRbR)=wP1g`-}2unC>O6ow=s{=NV6pfEo3=tY8 z=*$TKFk8Wv0K8B_**m*Q>+VW*1&gD#{#GSc(h#YQL?*<(ZUx~>L^RyAG3}j0&Q|mJtT7ec|Y7cr~ z+A`Wz!Sqz9bk0u-kftk^q{FPl4N+T(>4(fl@jEEVfNE$b*XSE)(t-A>4>`O^cXfrj zd_nrA-@@u?czM(o3OVDok%p3(((12`76;LwysK$;diTl$BdV)!p5Gj=swpb=j2N>b zqJ1D5E#zO9e(vJ6+rGuy<(PS-B6=gHvFat&)qr%j7T`vT1ju zIvHwGCk5)id{uDi@-e?0J*(-W-RGZs)uhSeqv7TA&h|CUx(R0ysoiQC8XnxL&RXI3 zO`H`8Pe&^ePw*`{rIJhzUg@MuhUL`IONG^*V?R0h5@BRDFgEF45b0jSrg0r{<4X)nw^c)uQ_Ai_p>ic!=K$pmnyqYb=`6fUo40ru#Gh= zMRJxOD(1n?Mjz_|IWyJK5^fh3*n>eI0MmEKq%=-oIdGd4F-LT>RL)Bp5FWxb4aNLNXB^o?YBSXQ`SwN zI*N~(CQW~P$HpzwrMG4IZKI>TVI4nQ$a-#)zV}LE(xgQ5MG@L#e!e@ ziNtg{Ph&qpX9FLaMlqMh>3)Nu%sAO#1NEsbe=#4Vqx0Y;<~+mV!xwj%}Z=xZn= zSqjxSH4T~v>Xd*=2wmHPN?@+9!}aQz-9(UIITZ==EB9}pgY1H4xu^-WdOFSK!ocZc zd-qhN$eZcN#Q^0>8J%)XI$4W(IW6R810*ucIM7Q#`twI|?$LYR1kr>3#{B{Z4X(xm&Cb21d^F9MKiD=wk_r+a=nyK!s^$zdXglCdshbfKBqa5aMwN#LmSNj6+DPhH4K-GxRl;#@=IJc zm{h}JsmQFrHCioWCBGzjr5p9L4$t4`c5#Cz(NJ#+R7q-)Tx2)6>#WZDhLGJD964iJ zJXu`snOYJYy=`<+b*HDiI9XPo8XK$TF86)Ub5=NC@VN#f$~GDsjk01g$;wDY!KqOh zC$x={(PT7CH7c?ZPH{RNz}Tel$>M0p;je4|O2|%Yq8@sCb7gRhgR4a*qf+WGD>E8~ z`wb<@^QX)i-7&*Z>U6qXMt_B2M#tzmqZTA1PNgzcvs|(|-E z4t*ZT-`kgepLl0g1>H!{(h8b`Ko=fR+|!L_Iji>5-Qf34-}z%X8+*Qwe^XrIS4Re$ zWUblH=yEfj!IgeIQ>m}+`V(4u?6c;s&Ym_6+pt|V`IQ1!oAC@R1XC3tL4BQ7`!TnU zWaoqG=nhI@e7dV7)8VzO8ivuC!q{hcxO7fo#2I=<`rktP0OfAO-CQE!ZT@}e7lw;{c) z@2l7RV$@&S5H@{=Bj~^Kp5At=Jq=Y92rXP@{-D4j>U=-a^gM2s-nIZA;u=fbm2BP=Zca5W81_cA>Tr z)x+r@{pu_la2Q(wm`Zqyd@GhNDNT&4oNHb_>w4{jIU}m&iXykMxvi;WL8;y7t}cp& z9CEpR)WlI1qmOq!zg4QTmzv#eP3>NLd7V-+YKmuyLFP533rd>WnvL$F3b}g39PYk; z)^hXQ%5jO(B}-TMio7@t<(V?7M5!ycd)u4Z+~!hym9+KwPVO^Wkhi^Dc7$R@)o$oh z^mRbgQ@5EvalJa}V4Bi3cs^w5pYtbXXz5W|e%+z-K;8M%Lf~BlZRvNI7=)cG6lbjg z?)l8iOw!mU`uaKN@UL4>d#edM9^-ePb(VICy6Cg-H^Ew$n_s801w`A83W!_Z{D+1G z(<9A>WB@>)D%cxw7c?Xv7N}6gg?&TkLX|0@k&VL)YMI~SsE^dzj2^3BKL7SM$!0Lt zj;ytKWw|(58n6_NNH$JVRh!W*wewMr7)H2jOCruuJAIIfPMFpf6j=hL!D3nVT9Dpo zut}|VoG<%v&w;HrQtz<%%T&X##*z5{D!!egoRN}R_Xxuy+E3dhx6!7mlNyuqsKR-P zlP#8EKGt{Ij~8kXY?&*%q)PkPG;rziWPd>HefyPwV49!>f&Q_@Fn{8Cyz{HCXuo+( zJMu<#{Tl}^-dh%nM0IrDa@V zMHgAog4`tk;DNK-c{HwRhx%Fn%ir3mex!XeZQ4QY)vQ_iZ(j4-GcO?@6Z-Y*f?u7_ zmf!}WRoGkI#BO9;5CFvMobtV@Qm?#eNKbbX!O@xEVhnm z6LFnWu=E}6kB82ZEf!g}n5&IuivccTHk-_5cazDAe+O!_j+dQ~aUBy~PM34Eq0X-LOl zjunFnO<4Nq|BL`!xwvyj&g9Q0(A_*xLT~l{^nM&kGzB7+^hP^L&bD7iVdXe3wobJXVX~o*tX$ zI5xthE?gAl!4+v~+ASbN2nYIqNn_#3>!fi2k=g*Hg_%caA#plNQR+RtHTiW>(*OFG*-nzu~6DMCrX>xzP`3sj}D!||8 zf3dk-w(NCUMu^C%k|t?sa>9gU_Ms-R2Hhm~4jNfPPyH!3Zy zV0QFf=MWK%>|(eV$pB5qOkC)uou{oIJwb_i4epV{W95%N)`+uOrLx7fNtD^czsq4B znAWb+Zsk|YX}a?b+sS-!*t2w1JUqU6Ol`&Jrqa5=4eeLWzr1DX1fWW`6MYf+8SOW< z+EMJ|fp${RJ7q9G7J+`pLof$#kBJP^i@%wNnG3fnK?&k>3IUVo3dbs9Nt)x_q|wIB zlBAi#1Xv-<+nr<13SBfkdzI?dJ|3~?-e>MzG(yRsA}I_oEd{HEGZ&7H|Km9mEbL6r z{Ubhh;h6_QXN_?>r(eWJ@CM1-yn6Y#am!aXXW!EfCpu}=btdYT?EJ>j+jeuc%;P2g z5*J%*$9La$^cy>u0DqjO#J%*IdaaPnAX#A6rRQ+sAHhY@o32==Ct3IF&sM14!2`FD zA))>ZKsccTyp$U0)vjABEY_N5lh(@e+Gj>sYOTgf?=82K)zw-?JX2d$x}n2Y0v%SjDtBXDxV2TyyxQmN?2%8zkKkKF*!AA$P$1#qrF%fUu~URt`tp3C_(>^tkcbHhO0Hh0A zpTVQR{DjsD=y-Bsl#nuTVKRxYbjpSJg|K+SEP+^Y*z3S9p(_-s9^YP5Zc?Vz*o(Qx z?f03co`dGfW}0T>UdEZaW>s0XVEzlw@s&bc+B-9;^^AGsx$AE~!1-7?tn9z|p4}_? zRsM&sjg1>#Rb#6jFBRKMeZ>I_4<%=&rF3yqUD&Lik@7<@2*(0rC)UqPj`Gfe8L&{S zhGtB67KhF{GnLZCF}gN0IrIPU_9lQ)mFNEOyl0tx-!qeCCX<;7*??>lNC*Q7`xe43 z2$7wD3MhiII4W*v6;Y775v{FSYqhp+|6)6BZR@Rdz4}#KZR4%=+E%T%_gX8-9KPT4 zo|$Aa1ohtUet#uro3p&@^FHhEX`OcGjq==$UeAQ~<6AZzZ|l75nn<#}+mo0rqWv5$ z1N<|1yMgX+Qmz?53v|%P=^&74bwqfH?xIC`L()W{|G`j^>kbs7q<$hb6fL@S za#nHyi$$TJ7*i!6estChR}QriMs#yy!@Po#AYdeWL~* zUR%)FT#4Q~O-N!O&it}b8zFOmbe=egH*Ka<9jT?dFCMAcagAo<>tKrW%w?P_A_gd& zXwHTn>a>WEWRzimu7EJ*$3~Jfv|@bLg}6iH4mgJB!o60eP#_N!xYrQoMf4&rGLau~D9ila zYGD*3*MNN?v*n6op+dQM!Kkr@qH1|^ zh7skG&aC;+$C$OSR2!ke>7|B6JDpjV%$Jo5hI14PGyx1I=Diw7>h@vzL?PLTzC;`; z?}nkmP%J6$BG!9mxz?+Np zIHbVy&<#H&Ekz1(ksSJ_NDQ+XHyg-!YcW8YvE5v*jFQ->F;|Q-IB@Mw6YP~v=jY$~9n@~8MVO{1g z@g=-I$aXs1BH&>hK(~|d>Y9n*;xRm&07=pLuqVYV-bwyCUIKgMdLSrovEs2f3{b z<++d|UX&}*7)y8){Ntc{RL*udOS8r%JV4EZ64fUF85n7%NAWejYbLV}NB|lS>SnYN z?PFpysSR*OodDcNK;OVKsSbKS^g;|bSdogA=};1?3rYq|Nc_tR!b2ln>=bNTL59uS zZjF^Y1RoS7qF^>LEqt<#Mu0ZjpiUNLtsc5%t*8}5lW4OWwFXfqGn-q~H)5}2mSRZ^ zKpfQxOe+KC(M5V`tz1zQ)@pTTQ2?NgStmwpvPCi&U9wd)m<^I-w&{(`Vb?Q*4ApV5 z(G}DMfgox!S_C+OTa5UkEbB#G$SC<8vLrDPPT_Uq5N~7`%Js5Ut3!o!f@HJm?b;(N zbbv90V6J7=E&)E`b|}N4n`VOOuvo$IEMx`%EkX8mpug0yY80enF3?M57gI zQ((b(;dv_v7PDKFgL|6)q^sb%Gp_aU)wp^uX96>jGEsOmBhyuDZ8}+y{bG?UqGqyDfYMtJ{6@xXI>fVC9g+uG zbQzl4fY>P6VAkv8GEpapl2>quqSIoui)Mr95Nuw@voGBux%Mq zYqG!&A9RXvoI%gZRwI->g2SYPB1tbg0U9UkC70cRFPTKU0L{E!2e?|as;p-wNwA;> zm}yKfYURNzE545Jz^T+srPZUGX{3qx0H&3ol`)Eow3xXj!2lx+DkB=}EoF`(n^)2W z_26hljpwvSdw}akJQN9;WAQnnHTN=3Ko19hR`Qqt#60*^1acxN84Oi8W-4nXd^@w0 zVpMzKqWw_(cHwQ`*uQ>F4F;Ncc?}XU{q867ZF>zihsu1j_i%f38%41S53RkO-5Bq< z<^ffy6fQNDn;z=lDz2OXjU+MMr0ziZ)HseHI3+}-N8v$8UWEK_n5pL6VPUS@YH^ z-F?^bJ%5Vt}@l0B2B$XfpF!7J0KUW$rc!~hPD3+Ms%)ia=pl{0nuS0_) zMk9rt16uqE&;%{gtVGqhUs{u$%()O~zzC_11`vYVVXfdfEU}YwTDn~JYTSiTDRNih z4#ap?$m%48h4*c`rhEH7?VLTW9aCi~b>z~)W0xM$c|y(8H%u~4?Yic=Yr3WyCvBMC z9P;P}Ra`!CY1TVd3~%qgX48EO<*6O5d**2Osm_lAM&ZKw?7XUKU$o?gjCIcqH|%NJ zuxtIAj>_t$YW%D0ShIfD2DzU5%qnHsRN0vm^B3-wcim7D^;K7~Uj8EuKZ;X3tlbVD z(=eh%wxAVAWPvDL3Mmg=TPKpMGzTdG=aT&qTw(TFBIg<;`kFOrB)&>#;&>KE1kb>+ z2B2dhdAN+pj}^ZH_t#P}WOC_RDs4ppbD0<}eknMnviR2G%#`AniYwzKw-y(_5*$-_ zmw5S-TNmxQbkR$TmM>p=*`CF(EG{@lszbazB$k;2MYhTooy&w{`02hJ3>+yIKEOe7 z@JMkSHwDW^-jsRwlSM}sEqQs-p1n(#FUOllp3=O)Tup&?1<^)a@`nk7JGz35N>n$} zBOy~(>fI9qX^_jCE*5|=cn@Q((|dZ4jk)4MmOAk+0xA#wuDRF-%lTtBwIA!9Gr9Ct z$c`7mj%LBTedqC%Rm_T=dk5?Lu6Ta&XaF9q!a$AUtk$ z*e$72Su7q{Rad`o)%w|Sbyv5rzAip{{VH|GtUY1tf`Dk1!6*HuN9YH|>@$Gpvq}N6 zCzbi<_XLxmE|LLdr@JCzPlDyUYO2J>kDK?krp5CY@11*7)8aCVVb&~zrEGE2O>>tojkD`+_dDb1*Ao``HQpP(giSRL)4OKuTMcNVOb@(m7M?noGc?geUJ;8t6u0>WYa5RLDJ>(^Zu~>-DTzEbb z=Pw6=C#Q(ao#It|Sa^jEBWtV8YNL5Ce+KO1 zHqBg6?QNQUAP0QbaOG=Lqb?5ZLlZP3JdqXFBbSG?_!QPegco`UzEDBCfy7n?l|5O(2uWh*{9fh*}OFkZGv)4J9g^Su_Z-y zktO~$6KAdO?4HIhm;a)+gVRbF%BNDw_qH-YUp3>pUiriPU-DaPao4J;%WF%Dllm58 z#~3FQnvO5O$UIv}o~Up(EN-l>@f8Ipwl+*yG^2h|U81N>`H9+~R;Nq6WZk+k_l_|; zqH`}-wki9Eekf?yVOxp~wx$i7mS&wyRfA;|YZ$pD0iFQM7=^Of;Mb5{*g%Q+MV}ZZ z4uCY|_@8q>JQ{}h=B5NG!svf6mRKr5#bVli@?ZR%doi+~75m0rb2XFdcTK&}XtK)Y z#n$?!<(KX3?3gc;rSMQ3)+>e{<=;f)h)dXgJA+DdJ5q_(=fbyjlD zyxOq~%LPEFsh*KmXEIW|_M9hDm%Gdrv97&s&LCvUqb)02CoZ4W(b4X%EB2q(#G5YM z&@wJkH_qwtRocyZt7Y4`(pa=cD4!kEPl#4{yum=*q|U{&O2DV&=)yXRws%3})r>`7 zty6tM=kuW2FpR*(!{^GYty*Jp1woSmG%(Qs4H^#!;!Q>OdkH@{*K(vzM1v#qO$_R{ z7+Jto9d&*4xTs#V1lt-9mM`tTxU{8|32n(X!6M-UNsS#R?m__F|Gn3X9 z&{djT%C$c`e{S8Bi4#KMy0LTS?(Vvq%{y6Caq7xk-@t{Re0DV4heM^6gkrEpL-{{% z)|>$4EU3Gq;JmPH{E@zsRX+#@>gc;qk2i2FwVHuCI??#%xdiMweM zWaT78*EG!|+OV634wd0UaR@TenRhksaP%AUUdHC0VcZ2nT> z|Lq#TX5O&2h!GYviFiX{IRHYEViDCLf^Wf)se&K4oOU>MQK$_!7!L(|E5Bx`dn|^Z z8D!P9pUu^~tYLFpB<~24WRqgt9Jadj5ce6JRV}}8O%6hRA!!0JH5LHs91WhgWWLJ- z!KL(|#^$p^amdJ5g8rZ$Ggy6?%`B;J_Kppf<0XMKcmmW9@>-TJn~gIShXI5aI(xEx zlSd-_6cOeEGR2J$MBqWpK*2%7D7_wEFG0(EP;?Sr1EpZsk|pld3%9nq47KjwNtga; z^X`AUY0HzBudMExSE>hYgVxdT>O;3bbp6&zv#t6lVjtU=7OitgFDbdK>r_jozEYb*t7qdj?MRk%pu)4==CR^bNgHOU-j*emraW7T2WR%b?1^<K?p<`lIUQwM$W=cui|bx}?bTOb6E1v3`QcM^BdcQe z=PpkFc*njs2H)6MH*NX+$l&D3bkD1=@_CF6^b#6m7%YZwDoKJobt%*>6l7EZ=V>@G zzzY{zEr!q?#B%Vk9VD%4E~MxbJ)hcn+q^0Z=@qNy9XNJiUX{8Ns(OzNq-fqrsbhbE ziWT!T7SLhKQavnveOJ`2^uK@O;eGSx?>nsSlq%#_#sdo9iphZ#Jwo|{FhMbfSrS>R zQiwFss8KQy?9j`|&<*8j64q^OVgV#e63^ksE_l^9($wb9f`EyHv4&?kqn<@TAOMm< ze1YGL4dcENbcWZd&n7h~Atmwe(#RoslRpeyDguGF}j}$MRo9?SM8!=4Q2wU($EzceOopeaHDv$UhoQfY3;W=e^g5xM87H z;I{8*GeL)G;HH8ITBt8$#)NOPnG>ql&Qh*h zWt>ty34rm;*F33uigBg#?eg{u7R{5>Q`U$R2j3@_Lkx_M{bOC#*zx1XR_*c*B-IGq(GV|B@o{8hJ3p1*lD@AJn%&$i*n1|9(=hKoMs|KsjeFu0HwhG-gj z6NR02xQ2KllvU2l&Q+ddYuKj6LihSj-&!x-tUR@F>EtCIlkybUel`o1t{IyqKm3Y# z^I%x~1FN64cI~X$=bbnBPUd;Rxn=jXhSG-2Z`jT3lX2q?hsL#({W072*)OlJJQjT){R0dcw$MIV@Im_3E)riYBiU=q`Y_6ca&e9uVeb_jW)Y(*6X`BKYM85 z!b8t)Ui*XT*XL>UuiVO9x8B8yUlNM}WBcAqm)&yESfoE>5R7X!w(jnYSbl8TpaivJ~v3;LD^f$vOykiS%0kDp1GRq zVCg_iC;5ATIf&(~gt_DK_8Vo2`%JbUh z9jfe_*S6Eje-d8cyItyiX=UK|B_;1L?UVG9n?6x~K;xR|0vZ5x!At8OJYq-&B}jT5 z#x}{P70vb-p^szS5EvI&o&q#3;_jrm%4X&6S8u*@Sv#ZVm@V<@Hf3s4l;7vm>@w-r|)yZS%w?(I1*QeIrsG=I+5nepzsGxrc~ z!pSc|SCA)uB~*o*q}1leH+COyX<6)cl^Ly@AOH2^A6)<8mq0BH{PW9E7WVFW74(6f z)`kEd2^SPxr15s^#3*QkxXWqEyk{wqj1GtNbEQ|(J1tK6 zUnIYs&2$CihuMv=&x^lu`v>+G339PrtlYp%HorK*>MU~Tjmr477+hGhviLYl@>d-K zU!uTPY~kv}%w^h&xW}uU?TFq&;?(Rl#6glkWN>Gw4B#URl`pWSWHsaPj-^{T?+Rl%;){@`StD{A2dwJ|V96v& z$16bph~Zles|b2KXKVo$Gy2J6qqP8xDY~bRh4}rn$()b-mt@e#Fwd)MdNQq8Y*-I^ zKqOSY68uyOQhX&e!epDI){mhNNM=IwXQLY2+&brLfPWf!2x1u(hS5ey?BxMlyyvL* z=no!g*pcWU2>q^rYg;4Lqki3-zG)X;d+6E=r*#^~7*m$_EGg_eQ=4jA+oZ8YMYWd6 zb?&a!UGBQcmfE7Cu~J)W?WPsCJoTfeZdoCs5nPtKdb}+(w{hma1+}#c_RZX|z*J-U z`YpG79lHe^?%Xkc?nU**&Cy^m+F0WA*VWfFHrCYF`F$mgbgj9#{-U|#cig$|;T=<^ z?0A^d|2~dA8{jc0T&>LodGPkA2Ce<%xn1wIlX?a%!@Eq4Md6Y$Pjh8C)#tL9&B{-Z zDl*AaMfM==qY6ZMs*j2-_o&#DtOvEgKO^o#a!G8V!FLJa99SgR=R+3-1WD>6kPt4T zQEnn&KOhDe*4&&kDJBfJWl@4anq%Se(e27Iv}pbO#r>3wvWJpUt}zNZYx9klkhS?P zCbrI418eh@4+uTT5z<4YR!}Wu!0bb{)|g-CHs~wgPLx_;gZ}Pe*r4aOmyr#+pp0lb zHFY6iYKHu9A$fn1?OWE+XV41w8uJSK1!e3*OLwh>v1U`ou!Z{BA27G z@n6d|J;N3qwe4uQiV3KTDcpf57p!m?0p3so1Ax@X#2IiaA}2>9&SUXL^1&>Xh8#Oo zQ?C?L-8M|oiJLpU6Q{%GGh;&0K{owhQSY%3!h1qcSn>U|R_L;f`cCNUO-efJ#sSbh zkg5Hb9y)Ys=YeAvt+X|EzTjRz37BGClh(UmXfNBmxvV{Ttan9870vRhk`;uSF?`m! zyWBXXtg*^vTY1s31F*aP^xb!Xf`+yrz9*G!3+V51{2PK^bPhMbp(nxq$mtS*2*~V% z(N&JbY2FYBI?V#24?IeNyZFFOpZ~&zB|@M?sbh`bnlV9zkG}tHdLK zx+5aQXm)byO7#8XHFtDn$5~LO*5aqH%?m z$2wT6nTmGDI)?$JimeWHNO7Kra|S#r4ugug1UgoGf)+&L03keV@p1OHE$p^lBA zt*GJGLDNniq=XZ4I+Mb*82pqbfoQ@+p_JGdB0aQaeTB!Lr#Z$97FjWL@MMe@Z^D+s z&IK)jih;Wbb%1MocDc@#$)|IKVWN*g2&aNVGFMmdoaL`cE`T^;1?Tcf@^i>q-czu= zA7p!sX62V=__ATa&S(g9I0rd{)J6Sdr^qB}JA4(U(1Y-`7)a4D)MA`g7I!Mwm6+KC z^C_nUK7sX}(ukntS*u>(uyyY=UeDi#4Mlus`)o8@(xaLmYhKp;LGw3oP&Rni)G|cQ z7Ur#P!U!VO1g(pNoJAP;`R9fA(}??`-wW?AJpaG_{Fi;Nu)eT^;QuU%IRlFc*+_>_ zx`&U5+e^|ih7FuRhmOU(m+aK71UlNUGH`jW!KA(Xf;sb)=69M;|L@O||H&xL zl74Wt!{fDxvzf&5M8E`Lo>IUfK@P&dqXA1j9Ysfw#32a=jPn2f=>Dps?=)zh0y=nF zlN*J67GXr@2Az6He%|WXWJyrTG^F6<|JoS+k`Xm{tCR{6!43_i__z|&s!LT*4`;a3 zwB^UO!_$ZGtWdT77?_S^7Dqv~y|xiDP)-YnK8%pxr7p+Lxp?4~wPvULd zUmZLLn47GQg>WUt!yAzB$G%F{zYS~B=am%aex&q3x^I|U4B;Xp?}AZk z^YIrlk>Jo6{xrIjl;V~Ot%d0#DhpmMHo+{Xi^Rz)*c5L{kRh`PE-|>;1QQ0h^lDfo zd@>|=U5Y91Dt-M)<#*Gl`Fr}3$-Z}Nfx!+IeZ!v7G% ztcDQl>kp+vdVk8V$G)HSg>V(Daj1A4`JRB+&HA5cq3-~n7Y2oBATKb2YG`uA6X8S{ zY?6>Vt(nsVyAxRF6YnNNtUn~CLrIFaIITfuxMVt=e)j}2Or%oj&|p93A5+|pOZ*pd z#pmb`Sv&G65piAWD5e2SoNSIcgY-cWl#06J$28$_X(YT)8umd{pHg7Zo=kQW0->a_ z7yr))>upwE8ZMWr(itk!ke5-mNGO~-u?owjq}8&~H}EaBRQUYJk_kzaMJ-j~1H#0S z1rxw$&lCSsY5*5Eh9p`{{~@y^&(mjM(r6cji;VSvEmZ0dZ}u7v>WxNaH@lu48ujuc z{04p_HtH?AmEG!dXI$pv!-8`CYpz_XJ(2siAQuczyy!!@pi$wT{)yp>!Xhe@`nl`z z1^zAe8p<`=WnrFL1*!@PPZ=huBJ={PS>a{s$9bBsNe$AX5$!cHKZH|luaOs}hA*pi zw$Rj=>@_5!LqS+x4X9Y`l2I@7_L`@81m(I&E!VL96$Z9khIpPCg?Db=MU?BT)g7f3 z1oR}eOn#rEov2`=TqatC@g-cu`;n}|1~nUG-Vnn;qJfhg6hp5T(E`dSLj-kY;GX6Q zi-z9$l?TDudYiv<9p*t?+4_WO=CNA5llp|}o}F1=q4CAqvoxnl z-+26xjr)Osgn&kH{tC8-tSujYAX&ByDk<0rhH0A)eE8>_MbIX>Z9mf=3Xu{d5DSGe z{bXd;!bUBGMEs02AatuZk6h5A3ny8K=vdpjVylr_0=J@48tARLevxvQQ6xQRF2uMT zDdlo6=qryT!$n?JVgWh91v4nu1G=%?-N5?j)BLSd2l{{#%0EAV&&xf1Dr{4qxZQ5= zL(D1c=mH9)qTh-=!wPQK;G!Plb9%5!QL&)AKmk+G}epRD9NQD(&9O0C6ZElh(DA_jLN=MkxobFd(kGnzu)+M~#d1*vxjpI7N&Q;y&0Q(nt9Ov@ z0UAx~93%#q(<@Bk9CzjhzLPRMRY32Y!M4>0SFb)OeWL#Q0u->@`-CeGuA;1us}BAQ zc@mIQK>2shoeQcVJ#!PiaLyd@Kj_ibnQy2+9_9fE%1-skgH%88v00xH6V6~l&y7;< z3z*+Y;rwAP`&tJ>jA`DJcZ`7&@iupQ%b%(G56`bmS<#9BG;0CU_T(luy zt=;C3Nlc<}xz{ z@bcSeLnyAw`PUGAL>*F~12pf(YnG!XZdkkO7$`Hc?ByN%$Z$rECfLDLP%2`Mw2Lkn z%iuczcuO)T(Vwa}C$&16nxS+qnzVRQ5p9I84;?;p=#nva%=pfXYl&x;$;i_ zP|dt~6wqbsm-{)G2ROAL$rK4<&wrWS4F}$7>VLjZ~K@NB#Cl zO&Qzj{Xrj9Q?1IwthH&{H`*sEN1LX>TEL$T9bDBnzAi-V%H>rqOSs{8i9DPnOQEm? zKnSNAa;HMY+M##OP3;`0pT=G%gsg(SQ~>24N?A+(Cl^G2rTi+Y_Xmo`>Wi*@@Y*8% zxO%^0U>2&c=s7QU*VIcq8^q`sm^J3$P#9i9SGJWj|-YQ|Bbro{q^IrwHjL#@aw6r zO5(p)w}zsz_FT2}`msf*s$lq^*3AS90U;2;%8zQ$AmjS~uU@58ERcbWhv?f>K#BeL zYN8qi*%SY*!e{wB?9^3;*7vWVA<6l3`r<8_4JXqkECB$U^#wWOuf$1XFNlXZ{n58dU(CAELUC!&Oi-&kb(YyL&bkw zFG94K{HSTIT!grnt(x7Mt9azgH#FZz%{*?b|DaQ#z(AfKI!4Z}p<~>Ge#1Se1*{80 z*9-3X((C!(%0GrhVCY#e9J%8rDwB&WM#Ib#hh$(WdygIeQucm3{$#|=Kl+eJTk1Z-(L@12&%MZxw-kLv=48+WES(PWIT1Ks z0C<=YX2Yy?Fc%$1$a>sE6N@S(ydbyNTznjed+MRp# zqQd(Tx2JkitUck{ZkFv%h>+T$y361us*p`!x@ITML#@u!?BZJ-!@DqEXFzk1cNoI{ zJl=+S{D?*ZKK1{XW)YK5yzt`pzw`QU#6SP_sM{sCSn6GMftpB-*B5YYd}6E1T{V8s zBM)6)8@_GeJO87$68vfVhG%-%V?Wnl^6Z65%hMOv_5&oUSnJohv?fUse?PIwpgrjj zbkDBTKUc**{+~4@My+3;_M*cli^%=z;`psm^74d} zCj*Zab%E6QT+owC_c5m2HMR6aD{F5vvrm4M^bRUw2oc1;q9jPZaA_vxsFaP~U?%O27@cleW3dOF$d>Vq0Zl}ZBVHjH ztf_?4md<5`q8EHId=*llqXPIzIAX%~1B?b5_S~HV>kar}&i$g+Smv7ZlTat1QzXxJ z$_Fac3X5RMSd@80O63eVgMA|`7viFSV3ZmRpY_8pOoLm0i@%=q@I7J=7Vq5YX9ffA z{>R`WG+DU(#C;6O|HMaLg9l zl)V7Zh_060KjCS9biA=f=azMILnJ&h}h zly@(WRadr83lyzrB*7h*#Kz%c#TEcwRZLH44Gb)Vv~oEAv$QE>6AfHr(F(C#@+ zLJlGHE;Y1|WL2(ysP_V;dWc_?Nl(dVTAaYOpjag5{{*~1y#T?AsgabJdOGqoA-oeB zE0oxN_!V3X&c0eE1?A93*;A)ACcg=udm8GzJ~h))e_kxCET|AT%Htl--e2VXnV<@TsN3YA17M0e6&-Kk=YQOE2LMDBtsJQIke# z@?QDP5g#LZ(1S@bh&gBDacz8F` zRpD-jIg8-ap`Ym@6rNlM3=JFCvr)2b9N_9ODp{J#8`v;h=Es?IOxlxNiKM<#Q9_2M;_jSYUH}t zqe$Y&x^->4;JRt+*3Xu{ylQW~6s%=u)@ z9}!qmL7OlT#T4rTQru(OPi>~6!BlKwMiZNC$FYcG5yvTlmyw#v=M)cWYQ~gfFJVt> zq~`S7oR)6J2?icV&xW6Z&I8CNu=}8Y!-3V5*oU(pJV!{pyvacr8HA5P0nDoEQ%(JY zi_HlS4K2djpeQwr8f|LDf-$pdJEIqbnAcQ(`R2Mwiz8zq+ZHaqq%>Mu7wuYe%n&tL zfGjDLMa5%lx}tTse#w%qZMbXkq~r%<8NgEgk(yfXgz;U~-7DFX3+bnQ@#AqBY=^OF zLbS7X)|dq=R(4l+ji2DHt%>*r30Rp-(iA+JEy;u?keU%+qc(@`QA$BS9Orf!N}fVd zAL_Iua?ljh5MAJ^c}*yLOiMzDF9{(p(30MIi+m$<`Ua+XOL>c2D0t=$9GupiRQ`FA z{BOl%>K)}7|3O^Dzk_}@em{Rc@>6mR)GzU+fJP3!_lP56}Ebt+|2<0=uUVxPy z3)N6@44izF$8~7*yh5H)fjBg#!VE4emB7mt}4}d2r)5g#{ZnU8q)|NhnorPaQnz>S+LontCn2s+La0 zh$jQ|3fkihRKrX7xJMtz8qh?orW`edrfqDgrtxfxOwvIr^UxInxzk2wXb_tKnHl(z^v|lS3R^;C5-qU z@k^Q^e256y0(|hy8uo+8d0&n6hRC-))pyDz3Z=lgVFfaOs{79aG081CD(x1Z!z{a6rfg{`f{nt;>Z~S~76JTgmet|iqonNy9qSRCrj5SG zE*k8okuHXMA1b|YZ0qc>KB6<%`;DPFQ>HnqYN&4EGLuv20mv@Zt>Scu^WHjG$A{{M zn0_!1B4y#@2tE)shK{KGiRKDSUb&Ams?2};;|q5pJXA^P3}#c(A}>+?UHMSdS`A5u zx!-7KdwaT0vc*icx+RrkWvS1Vqu=l9QLeTd`z1pXyttbcEn$YF%gs^<``o$khc~%U z9?(+A$FHjL21BG2Kpc=@FYF5APed6YZ)jh=UwQm-OL4H}p<%olMV739mlk7y|VeJq6h({N-N`F)AkKU*9A zZncuEumPCb0)>TTg$*!DALN=JPBdym6qG@%J)>S~Clne0KH`mlb{f%P!tPP}AjxA# z93;`Q1V$D?)kIu!LsQfhjw9EQ9F=y_B1`piC?(juo)nIC0- zDn9&Z<}dFxHQlKEWj$Lbgq~n;oLYO|eW)MPm|++FFVI|Qe8Ff4uCPwVdtGoTV=nn! z9Mg!5}_H(v@l9y2_n5lmXZ?=E&S(lJU6Imo&ZWZIn@mAKqMS=Au89C=0ru@=+;YS z)498q9ZI9JWB0j$+}686F?+mvy={HRr$^I7WzrL;!!dIDMD^t8ryc8UdcBwRSe?@Q zeCZwRQ~JDm!Eo-)4?J-5xd4^sKe}D^^(*(gg=;zY{*Cfo)5#lh`mXYC@C%ts-TPOr zx4Ya5jAH>O zc|Naas2cQjC5qX ztN*_ zp0iX-C5(oALou489mBshd<ac}LWi(CgsaDL(eO*GXYH2uLp{vr@SV&-2TX_wJ$c zu;DVWH;0OocbL`LWcxFSsKaT)I-4jmq{X-c2t|aJQkL}QXiTVMz=F`J*S(Tc{UO0! zi%CAn@koN|GR(ehQJ(p;)$Op{@wSOMEh&o|_Qx>8!DwP- z`FJ}oaQjgCpV#o@Nx!OH&py^S(Mo<6#&dsVsr*A}PIAih}WFPR&w zCRp$^BQjucQVv0ZvdTb~5Y%*mLkorYIJsDrg^}#t?y#MKoS(VfIorvSE~hJ+Nkv_H z1NyT0bd&Z4`Byk{k++vY9$qbIp;T4E&6tF`tlp*!>j)C5KxYI&p)K>A@*LYD^nxH$ z?vczftYFCQBHl2#E4np$pk;es%l>Foya6Zs>Eu9EYEz!e5Y{R^h4l>CRPYp*(qm5H z=D~}jc&KkX?%Ns_4@L11PWDH)q8*0URaN#UIU9C%a`k~+cScW=kFDx3OHQ<-c(1A| zhLPT?d~EY|Lya>!Q^W8jeqE%Xq@>T#)`R;Q;n0=BC`ofPQDBM+{rFksZ55a(iGAa) zU*eU+_dJAYMzc*kC0`CJJP^FOO9?7Xpo<{uSO7rZNrA__;wfikngXyqdcC>NU}wp6 zrPBc|2Xff6WKjHOlr*OB8%+b_HySNtDX$lf;WU+r55_k%G}>I?y}14c>;mc66GV=~ zB>p6tL*)LIuB-?uX}lCp$PRoG3NBNh#Q-2Qmv!*o*&zk*WvQ}QR7jc9RyUZv;eI1q z1myA@D>js9##>)#Y7`z3u*P$CtoC0yo8w|Q6F271w2yF)%8KD0_2xTV;x+lRX_)S7 zLESy7mmECL$tj(~EAaM1nhN5QP)RT+`Em;B3)pSP8(VtVYgUKyj>BSg0P|KE5JF0S zre930DlR@=+*Q0v=*uq{`_A#ko)-3hEcA%gLXTvULWp5*D*ZywDm-z#xOi1heo6D& zsfhffDTW$dtI)HAE!7yiAVDOsdl1 z^kJ2l>S9UXuCtekeIpWyAb)r;s3gmj-+uKnaX)3%EDkWLFD+A&-j7eww|&#xTfkW^^2cYa9_rm4Q zin3x4(yLf3=0BYT{IwK{%rJaGAcrfB}x_x6~ z?NgR#`|L{eSv%T*Hvmwtyp-4g+;<#Yu-bvpE@#a&$atCK%V}j(r9`g}0;71P)B2$A z^>07GDy&Am=Vx|<@=_YGAKMS!>s6Le->|zU{Oc`LG~#QV)<2JRJPc{DYNOS8_y_LC zl{@TCrW62$lakMd)^-st?P%lI2t z)Hp`>W4-6c4x>S@{PH(^%>AB~t9w+1&30NhSzJq;*3A}|Fx76iJC$XzW&Y(3cE8JR zb!47(SvFgpOI(&s!0&j{;v!y#gh|u^kVZJ9B^rTLKq!cWhf6jz7>B3{VIyUy6St8` zt}7v#!kob_%sj7rhkZ`%r086h2XZFre!9|+So+}e;-=^KDM@y(a^Sx%DRgARg`+6@ zF2u-VGLQ-ZWzz#K(++!YiRJ=~3|GVj`!3)x5$zUkh)3uGfML}Os*EV|5hF(UJ{A{; zN;^ys#azEYS4VvUT}QTW$g@cuN;(_~!om}CfZ=y>M0q>J?!6&0ot>C}-$GouFs%Hh zTmXOk#{D|~3BT@JuRegi$szQ;LUnyKd=u@?UxB<`_Ui-kIc(E;I{yK`ZY?|iTsd&P z-Ds3oUP!mxQvQ9=j3s~$dYyr~$?Q9b+{-|eMivJd_6zn%Diy*g%^dgph0WMnjlyQm zYvbd%&X(IOX1{WrZT72MGXRGk%-(<@szG$F^a0wjK{JzM4tXi@39NXYNK<*-69LR< zHA_JJax@?fIF6fq^$B30HaB2{+{uk~5)kSg_1^k+EuCO#z)8DSy4iVj*ToiH!~Bac z@4lm}>JH~j*Yjl;)*~sL(K7eK*OTEpx-0KkaM|Wbua?%#Xj@*tK(C(|>l{C&ZhWb0 zMo~pu{jBOKI=QucYE5gb!YQVnoLhYCh8f$YkM&BY2iPFc51wjZM;I&Xyq~eb&xB70 zb!DyRW$vzMsVFjQ1?9U8snP5KICcCp+z|F5YaW9djR7^>S60XQbPOU4qinn+8ToxO zNmqH=nTD{Wfv@awt2Of=f=NR|5D_7WgKt``%4VxKRM|4nPih20e86-edqM8Km6$g( zF)F>V8F&FIKjPI0*Fu5JJohBIjc8gc^_8vam+bbN) z^b&a)S?@-wcXYVkV5Z!+PTi!3PaWYx6x{?3=UUM zy8MhLFoOTujq!`V*3tMSxoiS#=D?7Pp0%n(Q89qC3)`8F5QUBrh37*5=v^&^@-+(> z0htu_oq#P)lq8+7G(S15;V0Pkj8^Mm@ObujJiy12bM!;%^Wpm2hU;Hg%d@u!H?ron zhpV7{3eP3fX1D@MX!O<)`U>hiqBVv!FrlFe?i{Tt*v_Hf&)NWd%*!uj=XwWu1V=%m zC=E2Y%d?O9C>(f5K@*3!6y2GKU?CtUfo5X3XhJ~Qjcg?3QbPGiIU@?a)bx-J>E7bj!{QCXu3mQVoR({~yqt$+}u$pqisO>>~0Lk}B@ByTU1@@rY z>u~r$XBHw_V;CUK2l9wfE-|f+u$d`;80<3WWT;92N!SjR2{H~6qAwgjz)%Q~BE5t{ z5sXHIfmk23I8e_Z=spyPNqq^MSm$uq;)aRIt1IR@rrxz|-rh(cR#D{NJiasR3>XYL zQ?c6>sGBu5Y=Z}>%ZU`B67$U8nWmTEokDOZfCCqnPOb^fozyaELUjAIxk6bm033#B zK)9kPDhNB1%fimKXjQzX&F%7()mOHa`eSoz%C&yCm5&2z3k}+W{3v)^aQ~O=ST2;{ zqh1e}hLNfmPB0wKxK4n)$lD{=B-9?QB4!5iAyd1#&(;uI5^TqO<*$<7Dnfn947Tvt zS#<%IyV#^N7y{04=lIS3qKa4`vUlFHyQVtkR$QH&Xo%Y!jyh4ywM6DmD$Evdk4Gmh zpTE=U_G_b+^J4zew#xc4kIUUw6R(Q4Im646I|U(HBwPXSFjgH1mI-sGZI4bs!_5s5 z3VlxJW8l7`)tX5d8S9bLfPC=@;-9uH}`2fVh;~5}+A$u3Um=pMOMiBA#5(f+jB~MSC zn)!Lx?D_0_9r0+`pq+|DG;S}OtTT^^ggZJy6=Tf00YNken;J_z?vjl`&(-CAEmN*Y zCIyenIJNpZr0o0Xx|%6Qw;Ryo*9)=h0Xy!_Sk9T#&@^8c(nn0QS=duDz9H!G1RKVe zc%JC!;BeL*S`*&RKFe1V{`u~DM2I|G-q7&DbY%s5VEO^&mde^;UG{pRiU8kB^nWzuB+3UUR4BQ7)%rO`tFm8O&c}Ju*E2W7p9T9;I7yo!5lX z(M02^IocHA0|sI3XLKxj9>WcSSUt~xtJ8+~5J5C2jfxN-A*?|}r&Io+23KzE5u-v> z$p^6hGe@ZSLfq%|`r@qnoO1>zZdIP&vYv%jtSCiNV75YUt{d0P9x(tvw|d2j+HuYB z@9tg+vR3!~V7#LD=YyVw>~Aj&yNQK8!ugN z9UCp~oxz?gj&*j#ii=|%ov~uJU}aN%okhQriOygttN7OrFRS%-*41?$TfI8-OZKsH zO_fIsv2DtwH7}(~ORJa!MK2%;=)9#Q0e- z_BW5)m|^T*v&rE5TV+7}mC2O(gmsyWM(^LM{K_LvffdF7!z*rZDzod#Dcu7mwar$` z*4sUU=djGz-40u=a6w4CiClcL>lMlWR2F#kgGfL)E^!$C{h|!XpPfWluYi?|c7qNc3!frpzTKbdDdEx|9tNx80$qoyY*K46?85f0sW& z!7aa2ZZbRGWXiX!R!fDr&>YFc1tlDTfX&`!!oS+D8#!ILKE()Z+kfC_7D`;pT=h~J zBhY)eOM-}%pyjLp^|L}=3dbtO3hGJ%;x`FW2IZS?*ETc@zhv(z#m_v*Cd`@z?SI%G zDz$1|ag-7Xu5}ewtF<)b4}(GsDA&ELygY7vMMZRq|I9nAAvVB{pUSXJ24sg9wMM(o zrY%~PNZvB0^154YNvyzv?6VoQqUfS5)sk!s6`k=rvd$y_Iq}U&@DFME5PHT1kJKP} zEE^;b^Tc&c&>7%g!ecN)VEqyZlqJhD3)xb|seD(iW8I2Rd5A4z ze^$P$IK@fI%gP_wWaYhW%I|O^7V&L8tQdZqg7Tj9rt(MS6=qfbuKb7c6ILP~P=2EP zosEO=Vggafln`{`kuTQ?GZ?HQo+QOOT z9l{$Ong7}-Y~1)3dncttGLMU)9@dYzj8x6t-@Ho*98n&*MR;;==JZ~1Z|3qI;fhoD zo;ZPVIc$SdeJ>VhHsNXxx8JS}#q7!uNUUwQid_t{L=-8{Fsd9E_Udc(|1mz31cb(?I^6JaRZ zOzye$B}*=ydBfR%5-yO9@4d2IXr z(+>fwmj~Z*h2;hVYeof&)GC0`+b19}sRuI!+(055HHC{*^C?{$8X}1Po$Hc}qp<{*!Dk8*^uyoeAHZJU8U%?shoMt&Xib zYl<(OwlbyH9~UkQMhyC~<8{XJKyk#ND=F6NBZJPshK^b8abrb?-d)}l>3Pm>xa~G= zd5ie;1B$=2vDk4S7Tj(w853+Y)IY!XJ2L~drKL7goinzKq9^I6`gfQW4iB zl2x2%Fos>-71gXdzIe8N`N3XMNYqZh`AK(2yynh_YGNH8OI>;CFJ22*)VG*q+r7%> z`^<8{Humn%zh7QzyVl^S-u|WnM2=W>gQWLXXqjH?v~2l46QA&xl}Y1RW&YR{?x?Qw zy0NsUFij`?*r{2|!NL28 zsjd^jAOi;(BavJnJkV5@q6Njrx_pnV*!;-$`QZm=?(7`rmYGiaFE&qk+!E>-H~;02 zBJE6QS+!@+L?QH>z_N2MTvjXVl;wk&Q>BefNa&bv=T|ex#<8>^A^`R?a_9izLs%{U zRyz#ZBUff=dwWf5MPreXAx*?dJ(G)?HgsNDz3k3))2?Or<+tCQr@YKpImX9s`YD@k ztXaBwY0)>8)e|o6og%Pt(%Ag!lmACj$e`|sn$To(P86!}giq}j+a3JN9kL(9`Y z{Ef9%UIYG44HLEL>^n)PM^>{TZ54Di;NP@qDndc2gsadLfSJs%0vZVKL>I%adq*nDoUyd%E&iq!a(OQ%d)xUk{) z(OY-yczEWP&E>UgH_q6-y0LLVWXd7s-ICJD&CSscan9_=7?KCFDf{<77Yc>TaU%cy zy(5Q9OUuirR3tkZR`1yN3+b{+bLLELcAB(Dw{0CG+Tm`l`qF8*ueg}y4qyR}!j*y$ z0Mxzk?aWg8)20S@k!zRW%qtMWj59&|43(l zRJX}G;SP2*@$+4~exA6>qSKlWR#hD|Yju{)(cDwjt*ux`iSPOxO`=Czlrud(#EbK_y0L1SShwjawriLP+%D;20XRBpcdlLLkoHhta{ z^Z{xF;tp98FCrCAgdqm6q(YM3jowOiLFwCZj(R6>PGxJRo2b$0UM!pZ&2S<>8&R`n zUrgV^M@nVkc9Q|AcjZ-*&4_qD$p(`w8qDrlhMGW8GnNH=QI#WB9u9gff}qu! zbQZCAL9^FW=p|LAIrKz`K!ZhG)m9I;zuz}q$8H2&*a%a$KunOLo)9!W|Th6I$ zoiwXyoGBg(hea#1+5+~Vw1K&p){Ik|XtHRPZl(uZm)?Z-H6oK4I$TihaQbaUL3@d@ zTvsiRyTI+9eBZ^Df>e81UA(Ofz7Xx*r4?S!lybd@%#`(wOq^QeLacmJF0J$!MEwC9 z1W4TksMIEu*=ouJ(PUsHE^jHTs*r3}vyWK=vfgKd1B`>24GzQqOWS*Z$5EYa!+WM| z@4c_KuXm)KB}*=Hmz!{J;EH=$7dkdzzy@rv=rM+bVv4~K1p*-uz`UjeUW!S8 z03o3UjIAAi_nDP!;gG<4{nzg@J9DO=Iprz$b3a-so`jY9I1>j66mTJ=@l)$fIt8a- zfa8&};F79ws#SG91uJvZ7d3mNzp6COmD?@8dbisIw|K)Gbrxs4M4>B)vAXKw0(-Mu zFK2j#tW2*P9+68698FNSO)Il33nn{_;Vc!KV{kIS-w>VoX*u#mvr4!&8GV8y#^Wl3 zoNyfBTrAIg#z^Iij%YMePQ$|jqGkzq@_DtxX0-zLY~)PsF1^gC@L183@s-?J4nk@) zXxVCm$~IA@FA9egYEEek1ls&&p4I4bq;|DcrEAt26jFy=nx$o>d1Vbz!&7DL0fk*} z_0V+QbIY5}SCuV&u6up1g?L;!`r&}3Di6xhT1ghHCIw(Tse_keCZxa!8>CMEC@gPmB+B{eEN#oA z1IAc_fg+2Kz<3QQEg&oBsg)HQoGB8eXNjW;IHZ6pDjz~C$4PQ#GK{|bx=oh`b&q|v zz1ET?{889VCXFt+_VV?SFlU^%X2a!uS)_n{=YRe%F?-2%{a;~HXGR@9(J^Ypfr8_`djf#7FG;gj{on>7Lh|!^&$cLg14JiQ18@Y;(tRcsrUG z3+;eso*#O7N`aS=bwnIyon$&@w6X#g2swm6!^;6&2#s}x&kI=yAv+`PiDpH|v|Rwd z7_Chj>zYZtg~AX`Lo5c=K`Me|#9587gAgM8 zsU=O3_6aq+x~*BG8%oC%=ahI#O20kOcJY!%vgm{TTjzJST_v1)a*2NQzy{&z26?Mw zYz=Djv%|PD17Ve!3((nH1d+{kg36>_HLwOjNdpL5V*u z=6|HfKUmY*pv6QRmWYl&qh+8mnc_e+Q7Mrs2td3+mLH7y0U=4O)brQ;?-hu4YAon2 zXoRmw@qPYZJ*BY<5Wu$0BdK|9;HDCKwmrUW+v5bdkX$l;yD&#*1abG51&xgbAU1Ux zb!6{$;b3k>%ws31MT>-#o$a9~Y|A_=ctwsQ&Yq%!2ZUWXT|}Yx++VnbQD=kChukQm zE0T><5$KBlSO>8v$U24N;?uB6nt}y+0ebqEicfM>D5AgY)k3dW-V1sV^3vJoNQr&a zBJpEfLz9H)gYk>jT>&+=S#6;qV-(Ai>2UrO#wOI-Lp9YQd+mhm0yu=YN#_hOpOLq$ z?L9sxnRNOI zjpoF3Dd1?Nq=(lT)F)18^w>*EGJDnP%wFMT?A2>doKTD3JjFkScnu?3s3c6sH9D+G z#SsvhI>TaCS~25#c}SF$Da8i`4r2pcKmRPRctm*N(ELB1MmX8lt1(|jrVAGx-$zr- zu6ULhZ_G0o{S&6_I(gly3$lG$*{67$@<;matPy_w=2j3Nu7BpmZ`Qp`-1}}Mwm)r@ zGTGU_k*}<{?&PjgqfZ+{pU&8%Gd}HH`ZdI%3S+VV-*Eir`nb8|5H<~F?$92LJtrl! zJ4>--?h<1JiKIVCi$pIhx$7(s2YNCi$vWLD?SXxuk)pxS>T{t0Bc@1f1{fD%mj=B; z;XosWnIF(9N?{074C0VzbMT{43=jkn=!aQWX%Cn@nvTK|UT%DjHzyls7Ntt(v{h?$ zkDA?f&?g&Ss5(v`==gmmFs|OmcH9TPRnvXPokB}G^#oBq!5}5`!PT!K7QtkCme*%z zAwPG2$`y@jw66f98#n)Tc`w2!NhEV(<}$+DjO3yxop;e=xQ%bQsx2+kN)znAayW6$Ci4qlA^oC@uqVxC@94?~JFB#t zbTC$N#^8$9-OHxg9m?S1`8#T)ET_vMMzxja^>TBWPVXttjkz_9)TmJM3<5VCH5#Md z8h^YiZgy#93B@mf%WUiBbrG+F z4;Z|sM-ba&`ZK+bYeOii|R4-PiVHNXH+FB6*2!InG{fP0yA<503J#ROk-<} z*re(pQVIiHP7%pk8i5N!42ldDFHjEc5*Nj#@f}fyYvLvaXu%m3ow*%!j)9RDtFd{^ zN;wiMdSnK#*86b&UzRKyQ&{-w!X-1HBlZfXcfBwCuU64Z$gcNcD~PmT{W~Eod@OwX z`qnE_2gv01hI~${)k&pSyit&!&+uBMx^ims%5e^pJlBQ?Gf%3w=Wx8!UPH!DER8Bk z%AIm|sIKnbiS8n`&%OTZ{y>XP>+}bPWx4ihTs+9vd|F;LeQr-EaCpYFsV>jMH9gn0 zXl?)4mHFA(eATx3bxo@uUA%&DsRI|cC$G_}(F&OA+WHk5ElBf>RSTFI)7Mwv?s$g! z9u4kp&*n9wdeSRgPGgCy>rnHsxKZk>D3m%u!f{r%SPlz`iRO!^Gz3wo@Q~UKASs|p znM26XjDgaCXie_?gU|l{;N{N*g3kzh(|>vxFm*2e@SoBTkC-2kxccf7e68T> z7tWjYCb2(3hP{!_5k7fy7TMoVKJvaHpnJl8NM(n0kkb%NNVF^!RizS`MlkbYEY>ox zo`BJov6a(xp04vSIK>Ni=>41)8V-i1I?O*>+L5Jnm0y=NY5M$G(?`|l4ai} zb05i_8yY@+(##2C{mY-fWO=68P?#bXkXFdHkh)j>+6ek`gLtm^RV`%%XTz7+D3Oz z8rxE?({WRsGFyGT%E#D7Ztkk}8qs~&YcG}AstY1av4oRYfPwxyTz3>nZWiOKLHqq)>>1s5FqT!cnZjT$io>v){#=BbB;qt1GGS*1GmWAB z&%t19AH`Ow2g1hGk^bj?K|B~zMNog{pv-Ih4;cdn{JA;*EpNa;bUhgw+xPG312QtX zbQ)xGi=-T*fK3#~AfXu(mi224wJiu1$y#_nBhY* z?N1NAx0fjPJxp@yww1qs5r~VnzUy3`LjI(8{dQJmaFo_hZya`>On5()3JPHE%*d3Y z{4VAjBJkF+(2p_2V93OblQHR1l^OFE#d9IPn|^6L{ve`*S1S+xZA@Ndyo$Rrm>bn( zdAC+Ca4mL~b*L&!bTzu>o}2&j&dH(vBX;YbrE=jLQ%~hP2g?8Wq*^x3-eYendnob0 ziHBgAc9G5fXZ*ve+;EJJ~ zrU!<`Y~@l<3P*n1t2Mp}7=}V)`*iTvs6`=Jt#jIt(Fbxm8m|M=kARQ|rmvt0%^yj> zxl-OAVHRI-ODd@`$*MX#s}Qb~Ox*V~NX`Y*J_Dt(3m;`Vur!6dL3z6sh6)Q<^GFj-iI~arAz&Pyw!emlrWp$-_ zp}bNZYnAnfmWI4V*A)qGL~@D{tON0#93{ueQ3{piG=7I=baJ47K*L2e0PUk^v(nN_Hq_^KsVXqabL;TRA*y^fdwtP8U||3%%{Y4=vh##I+~ z>Jq{W3Hi91!VX>HMvtX-Od@aJf_+YFO;;lC=6GfYfL`VD@$}&MZ5C_I_?o<%7u;d* z?jGlQl| zhSFC)I0?YGN!x?8q>fL7>&Q?L2@6Vzz_an0jg2!4pDI-6C@W%YGFFku?(d6L)P@Tm zj>Nq(RG+Q@?h7HSFnTd&t>j9uqcNq`_YX%#E1Fe(MvxfwdXto>Yv)%Qey0j zk+MS&10M;|?h;B^q@2af*$l)Kh9@n~*|<94%MXPs-}ob$_SRd%rzHLvdtW&H&9$p< zC6+(Y6s0Ni9qCCj|PMBy5(bAJooxH476d1n0HDI&v_AL9~=?{dP|bgwBak5^Q=lfjY7T})HDR;6N|8AhHZu`6`CCI7&a z)qZ;IOB1!)=&Y)X4JU9L+Ftk%#5q(#{Ir)LzB<#hLZw+Y8Jtv@0N+XrnmT|LI?BDrrNiJgMIV>QbpV^ul?g6 zS8sh^IPw10qTy4!!kD(tj1x5OH6R%&dL!^bvZ(b0`Z~3*m53liw3!k(9jMw@VogwD zn@H3IxCMnJpo$<*fgcZRqPqtR4puvWt?OVfJUdEYbg*)*dVQVn&pJKgw53IB*Az>Q z!m+aUc)XqbHr`%_wNov#Lt7uNf1VbG%bo9c9%e)~n_b2)z zS*F+3)#>z7X>qaiHCzmBsXI)sS=LqD66%%`SAMuG-X1S0<}JeWvhHw8aj;6~^6Y%! zg`HUrUF8#JMwUzm#~4G$Q(8|MTd)rG6coo((N;y9Ev+Y7O<~bMO{+(&Ct6{&qEI=J zXabW2{5n5fRj6f34-Jpl(5VMf5_?diiGLo~Xm~xJ^KuTa7leYkg8XDY>B{`R2?&O7 z*-hmKNxqNzU5YGE8n~L9mU#1WYqFgDmj~|oQtI%L(xD3xn0z=?h&`(>c`^FbpfQ6l zKqMbK14|KK5aJ(X0}tWj13;BpA_Lbv8qkkmk~6zk_O5hCTzgh@jalI`n_T3w-Snrs zX60=w$e43%>C9nQ-KeEYMhPF8T`u#QbzRGsjV72(-KO&Q*KIPp+@|$T_xjNYUb^pG z13Mj~ZTR31CYuv-sfG-`;y^)vdyJ51#tr zexk0e628upRT7j{d<|gw%BhSYB(<#F5K+H9`;|;8(G;YFn9Dfnt zV8AqTc76Dt(w~#z>&cBTz4THSV@dy=3>O}w1vfEf>}eIiD!HEfxIddYjD5?5t8h#! zbC`Jl1UAb4uG_or$P}Jg9n!z3T`P$1kwmYf6)whn3|Z6D{v^d;Ln4l5#faO%%*MIh zhqHFXb6xJ7xbUxm6=u`@8_gzLV&aBlrHvc!eqdvJ)8oeywHsO6&>Cc#Q{9LyHjpu? zDfBm8Ow>=YBdcae)7!IOHZcpZ8R~xwtK`Iw>sKksKCO_wgt=p@dd{M$C~Rst#Wl%mQ`*2euFzN+Y!(PRk?B*lRc{ckhUVvz~+7*JzTDEd29}5?fTlJ z@I%r0ZRA!qSXo*DLV{5ZZeduDRGF_f9rG!(*|h`+B*M&K3tLv7H@sqDqSl+J*N6Ar zcjWr>82G~Yu*{?OI>J`Jvp%~6Z9=K{wOcinwHC%1pSI~nGv{1t)$45RLakM!1VV^t zvJ7FXL1$%Sdgr6P#i0Oew(E_iyf$Z+o<)#{FX?u~VvI`n25*t;q!8d4Fr4Rl{muf{ zScM|rO-KisF~bsy+VTyRrVgDVKH<*ia#@8^VJerY`o}qQedPree7=eesUIj3j>1Ku zQ^6LR%V=cGN;A+e=?!Dm(qiE1>6J4&t`XzQKY;@+mrO%eB?*8S8EXjIi3lG@8-ag> zT1PUyOoY^do`PyPu*(Cd0QMT30+cUpM-e#YgN0dcPkh5s;qSsx;p5j+(dw=dU4TaTxMo8oD!HI zMyJ&oq@0=*TJ!VWW5ph9nGFq{NkVGd>IfSs$X@gE9m3y!yLiPPh`V?4 z-5ZvTNP3j=usLRTPad;3;u-1E*oO^Ywdo*6GqAV}$Pix4lHHOu7!P!Ca7F1Spvpla z0tMS91Kq8)q@HDMkg0(C^szET?+_Rva0t4-t(@ix!WmI&PEX)iFtD)+AN8mJybq8! zWo3#2)(BQMHd@cr5t}%0a0R`4ybbq_*Dq}wzh?3!A478$3;qO;D{EIera!rS}GJvcS^Py>|TYrTPiKZcyK#3eS&(>4A)q-m!fF zy(9j5n+{LZ;lb982@3=WJ6tv}rlQ`prcllYx1v z{)$s4m`Bp>+*@-Wp8e;!`NxC;rdBw4OL=VTt}6eyQD4=|m2%GQ=i2UTopJSeoiD5; z*Y}^)rVC^mklrKS2kLJD14XwQR2VO?hz~P+_&76f+O z1UD9EkQx{%tJepaAP{f>-C3BDO1@-_TUy4DVsc!kvFX&TP3J^69sAWIy7Fe=B)K z@;)T7(+G|90VGg=rX8Fy`$I0GF`k2|g{5HO{XcE9Khr*buKk?5pSCAFoY?+EyW{`I z>;GTd=ef^w?lzyK2BA|Dx+HxW`k%AxKmTbh^-B*tdmMuXJ0va8f4cJ76T~&zjFYqh z{vQ@nIPiWD?OakUh2v*V6~6wt)d$ZUFogH$XID>ATA~b}40HBDfA+Ng|HH9EE(TeI z0iH?E_3=IMBO?Agve@K>o2wGOR z(3=6+y(7HS|GWsTO9?3vT310r^Z@sVAJP*(%3$j<_LLOtT{`HWrHE%7gPw?~mg+r_ z9jRUd_&&s(0kH>Z)Jix2Tg7}aFfs)LG-*tD$kEtG!c;RF5T_uYsUwqWJ2uo{*}1+( zxMy5v$F>%6K`viKjE@EC8*`h#sBcWSKf3hpqhxsPq)5&BPP*JcW_ONj+15c9T&!l% z$QAqA=yGrR*yvSD_O*{*z2xS?XM|5z6x4cD-II4sIQHvR$3`xyY2Uj7%eH+h=C2;z zzHiB@(d{=cfo(5|n65sINi;ST@)?Ywbk<3jGOvm^W%`!S$Y(-G))Zp$XDlDT`<~t7 z*)OkoHr)Rr?N)3&{OmQUZ*IQ%8+DNhOg!rz&$iI-kjfA8{@#bcMJTGBUj z_iYgVXF>Nf=|__Z(9+4@JW5QLzIU0yyJT(2-G`oP>%96+chjaR4|iqVwRXh%aaGQN zZ-_4__CGJ|KY4hQRx!`dIsPwd0}_psc=!Sa*}EXAng@P(j2M2DLs!h8(kW9DTVg{b zCyPoM>Ipk0>>!&i?7eDHw0&IX{kN|^@9>iw7-jQtvX@-HC3VLw7r#_@xvH&rnM&YV z79vRhcR%)m3D@-hW5u#ta>|xgj><6zPe0Z@U3lQFW%IK-hAGY4AGmkxC3pNb5F;0? zt7s(3PQ0I}Yl)nWGWcJjkOR)3B`9(;K;?O=1Hi~aHCV*|4!%Qq!Ym2W2(tjx1p^O_ z%O(=pN~8r>y>Qi4FQj+un(uPW?`-h-Zs@RdnX^{4&S#H4v}yB04{hG`&~D*hM}!gT zr?;R)*DA-ba+@6&|HK#D*WtGz@tjzwsk8`KFrG#+`- z5LQc-7OHrJ={KbBC}Zi{(|$)$)6f=07#CmzZ!hm%wyamsuk5Or?kFp$S>v#m)^=IV zU2K2GGjgf|bYX8Tqj_c!X9oMHg(OF^ZJinzx&v$*9lLN@M`iJsNIF$**kVT zzjKEKY~!aVNWTE)Sp%zVKJ?@fltBt^XFv?`wV*&*UC@|W(7P7Utcr;!uwM}7prNrQ zS_7aG2}e!PdA&T%4k|+cTm&TvHk_cqHNG5Dy_Id&F~U^zeU(h72rwh_4qaP+UXhRG zo~eppC$ejr2eTG{K)#HpqEE z@fK$SNBuA-QrH+ZL!f0;6VxAV9ySVLAjgqrY5Ml9?1{;YU6Gb3>+eS9g^QHrKFh_1O$xC6bxt*_Sv@CAs7DRfH_Dn#k5n z1@u25ZbBZ&f{t=rd_M^!E6RV3_YxHlOox8-$OQcqXO@^B0ind_8d&nj0plnk%8*0o zbA*&cC~-ziWY#k}QCj$vDdK#V?85RRvI_`p!;Xj}7<5E-7=Yp?*PdCVz&Vc- zBEtFNV#ruyk>moGM6oafY*=FK5rueA$6$E^r8Ev_ury07HK8;l+7k!M0VKfTb!14a z1UJw7JK>_6a$HtEYx|PF90WGN-4pzW@W&f>7X=+M@479-_Nra$2riCo5+1z&PrWu@ zwom1`=-2y6{ydAxll#&+ejw74Wm*wX0Ymg2Yg0Ya3B0 z3wwPz@^EvlI(y1F&LBceBMs4aEuh% z;i*4`b&}7$ntt3ToaYt3@RCBN)l2q!iNTA$XTbj}6%uZxM2i`gX0)#XW`7)Fd z(F7vK2uy{5NYnCC0Q}GH$gCqE92{t+NJ(NsY%e{|ge`00+^x(m(Z+~SCYJ7|b0Byx z=twZQh1fi+NmeZGV@z>OIkYt(hcp_nDAmydiH+U?#veV=C>5X)A{vF2fa)r&NkQ3(-heM@gEEYzonr^c(YK_IBQTJe5D^-}y z3aOTC5#G00lrlYIG%|Xba=OW+l4A|qa@9dd-XTCLuy zCu%j(TXnB%jZPzxO4Wc6z-|u6`rNxN?Ek06=pNtm4DlM`l^5Q1$5)I>snsge|N2U) zDLclr>*WY%)l1V)lD`wBOr?-%$l}x{g|1v9?Fz%iV9^;;I{r3#nAUQ)exEvgl${dFuG0rse z4kn2ce!=PJJ1fz5F2R_DQ4^DxIBX7xGd7vQPxC1g3bv*$TsYXo=848Dv!H!b{R0k+ zOmGOb^8(^VZLl=vpqfEDhItpSjRhnNEuuhe804@&635@D88L=96vkhecM-U11vsLN zKjMa^>m&eO0C%NedfQIcDAmFr)MOToHA_pt<5gN+b*&dc+(gK7AjFs;wbyawo z)%KMgMOu#AE}Gcr-6?5w%-t+p>QR$Q^+_W_;bNrsq=Xsc^va5@P_94{AM@L*g_ANh z;grtUynKa@Va6}LbW_*fl9~K+`NeyXdnQt`imwg+Pg;F)6_T!}(@*rxML`pvv&Wj+TU*o7~HYmz= zLDV=~8vogvUeI#K{*;Ub@iXDs)c!kKgx9)f@eBig0U~9tUVb&hBlenM_*vb*pxW5f zqVyv2k=d!2+t~o3J(=qfrr2(FT4)|&K1;#))9)*MAj5N-$s<4$p6zd$dKml5>Vbv= z1mPK|rrux#`v&PYo2d+_D5wp%5eh+E2);uT`?Hk*Dmcf8dAyRxOLIt4!7l0`!REea znuJf==W%L;pAb%}TG%1H*Zkzuzn~gETe$F6nMuw`IXGZ%UAT}Kh;z}R{W25B;yUX6 zsFN>+k7zp(u|(o{lX?FNDuMozUMkiA6ifKGp`^g|NSPghL!c82rS<&zcg`ZM(=O}C zX&TjDU(_XBJ(cjQ*Od7x>U_WK1@G3`Qe9)#xJ--EuM;~Eg8r__KHX2fQx4+Xf6+T( z2#UiS#8LGM;dVd!3S6pR(npOSqkES^oc;yRO^`yWkDijk@k@IlwwxL72kkOJFoh+M zhr0{U4A2dLH=coC%g=w8ASGD`Op#&@Fq&c*G=Zic(>gOCMl-1taDwzdTk~JXz!Z`P zF*_E?uX*npxn)*rlr?Zf%=N}0{lJ+&1ctHSLr$Jq1FAM0?{lTKg_1t$Uv zBW3hkVWJzD?=tPL64_~||H7|DLBCXPLZ(Zq2vHpf-fn=p^iVp{3vE`t$hs0m5v7o& zB{%^(_s@P=0wIUyj=T%$S&)q7E2qvD{9vt#Y?xrD`Pr#Z%t9=POLj4>7Og_~o+yw^^Ow9b@)&2% zCAb1oXQun;`x9k1QKIet+xJhvb};1^zF8fO9mQB{qrP*5BO-jo4@vvOI%1#Lya7{&d48vLyz?3}H+{eE)=e&kL-c~re%iXYG_KKc~F5+@dTDxx4 zfmJ(iJ9_BBr>bO*rs@Wxuc{=T{GZ$Em}j4}T`GKit24jI5MO@P2jI=T;FY(9J;E2y z^&I%ea1uM*_pf7p`!^F#9nG3IW@7iODUZK7;L{g!&L@zi zI6P=@hVEwI!;n$XpEH^GVA04J!mWR1rU(xT5C86WY$?{h5gzO$dQ4tlUO`5t@8n+k zo$xTxr0--)1N|>q@+|!?1p;g-R!{&-&IM%N`=Kpc`rjeD4!wWzBab{X?R_#2^pjs~ zAx!8H*(KbVn|?3bmVQs8VFI>n2KkAY03`YMC^;O(gVPt`*Fc7ym}!$#6~k1Q%Rttl z*blLyZ6fX-ehw+k&R9aFO?sHP&&!K2(FnC(X1)n_WwL6?mt6Mw-JFg+)rwHwdp^Hl zs``!#XLODr(TDCL_S?zHKmBUMW%Km)>ZZ;_XJLt7cAX>?j-E zUYR?pp|P!NN&UKenErx4th?h=qWs&P7d&1b&0TR@)lElk6+XXRY8Sp-w{w=cP212^ z9&gTR?&@mJxoY*=o#!o1HkMWn%M|ROuPTnk1O9i)y-A~L5-2|>Xdsk@S1GY20KzCs zM5V|hi)A1xGiH^Gxn+5fz#z@MnR(&gq5n*uu>IiEUH5c7ed?>H-R`HmnMSf9Q}6=G zq>5!{Ki%E^G*Ih5ffUwahnt>CuW(Ss6~VgVm|vPs&W=udbu%CQjA{6 ziC_{jfE}X|4TFc?Ps2B;>6ZrM>A+I~7!h5e3>AoY7lYjkIA}ek)?%;RW*oqlo8*6f z7Qy1NWQCt^8(uQM6OinvTjv6uV0M0vRx>|3(rhAt=-%4vkFuO~l-oToughfe1t8UHkOQTpF4kRD`LB6e|+5u(v^{W#I~k}o*RR`YMNxRWGzrXH)680 zL_$$O(C`mR9q5H*5q-i2YcZ@=G>TCM3kHxtwsIED45bvhV?z@}Y=#UVAKEPGUMx#+ z0bB+H<-lRl@(`GGv0KDm;)Db}MLdf(1%R5*1j9h#rol01f@LTSo?UoUxMg9LC$HhU zcMJ{bzl^oIDre5D^qRVYyu50maLdt(2E#koHRP@PRIB~O*L1kDyQpkxSy6Z8;U?cF zTJ5L)#>3T+$iKURM5jC!ODfChttojbXmuSf?XzWrL{5`p*N{$coiWI znoB+ueveq0-+y??B_EO+#IDqQ_|Q*ukhzW0SMCiImsI{LZ-SaJxNFM%hsaHb{1p}M z*-OtCJ_+3W3W)916Y_plS;9;ioiib4^wiGVnv7p5m0uZ~ZtI*X7ESB8t=agcQu(E^ z`L+%w(#WVLre)fq znR7$!ot>e`T_Yrdo%hfB1z%-qT$6QEyc|2p%~>48|#zg`tjqsOT!yIp5+rt=IdBPbKK5`=jJyB z^+%eLTHa^Rlj|-RWkDrEHt255c-whUEDS7^_m$^s+>R19y? z`@uwlI)&{73vrf%Mpr_D<*3|fDWyLOL+SvlRUAD1mB`<6=uLiGtMn> z{$s}8dCR?fs%xq@Y*x2od`NH+X)?Lu>NK^gr8Bbl=(>0Sk@*c;% z$1&4d=hbzWc;ukYlUgD@(!WX%>MFJ4C)TFF99da4dQ^3lb@u!@?9|$>Yc3%#y`Wa+ zW^aDTCXYmY$S&y3A6qFLbyO~Dzq5wR9)G@@vmY39#o@yKr}8H==S>gzr=<5ze&F}f zSWVBQYBB?C9#3_Y2eUUk#R=DL?XyKz=DJY_3EOv;R3MzL6eK4un;VCI7+OfxSnX`R^TYKhc{kv_@ax7yJ|`TKC_x6 zj4anVF&a`>3>K9h)-b-h%{(?C2Q)nS&-jWlNu6AqlxN@96>MHLuEFe6Rhu~^t1Mch z;W@dnEgNPhkU_p}@|&yl);jeSB)6t9VJWW~*)nT%6+gB~Tc##FPnQ32aqe=RIm_aM zk>;jh=5Rp{XP2I5w3>Jru}D7n2c6~NSk%K?ruP)(t~$t> zPm4U^e#ppeB8M#PqjcC4N2|fra^|Ot2@d8!yhP&y3fQPD5u&Ujlv$3VS8P-w4S{=J zEMb~UvU3|7bF*1TY0Qb>% zWIM|$IRmr#?H7?vp15z{{%N}Y!q+E0e13Sx*Tnnvjve2i{ZPBWY4i z_f3B#ykYcc6(*|?3$tuc3O<7u-#s~(jAmyDfwOmiQ#fo9@BaJWX|tndw$E}>%jfn# zdl|F2|E~kjkeL_D#4&-&ANX<^UAB};h69}+?Ew^0s1(s^4nq%wN%7-Sc41nWF^Gts zVNl^pK$!U9zI%li&IgMBGNn#0YkO_={3kCTGv@Lq=g&OUav4oWEdUi5i+Z;%BBpEi zA@VSNauB?CT!iAWZsB>#&2`Oor9*zXf>F+xkJFFhDy@x|BLOzW64K1vTjnfT_wo&y zENw~f7xci0@}qatLFSW4vb2m|l*2(D@}p?7twMiBvKB?~xd+KL=Qs{|3B>N92MLe< zn{TiVJ1}O0U1!^&eVy0B{Pg*)$B zvno3r67>k$Uns6^Fz*OO5H|rCC80KIiY^@LaUv))!AeSh*>m@uvrV%W(KMB$N9bkx zD5!6M*R8j|_xN$CB%O8qY#|HO>EHoO^7!%oUTP*CEFluGIbfTSq+m2orMMsM5rADi zOBpwCm^cPz#)2^Fx5P@bhoBBA&mKl{%%fpCuV$efV?r(EUkyv*5(%b$Hp>mUmWfXNs11uDEuozE5 zR|)R=%UMtGbm+g-bC-kp+AUH8=NYe{FOd@o&!* zdZ-eIIguCrrV_I<@2wrT2i16TGjJlO|I$$s0Hk zS9X1&pi6~V@`QNp-ho>gjl%}-k0;9DRK>dGfXm01hn0@?Gv}Cq2!Qr71d>OhHa?t? z$^c7171WpRQ!j3h z32zLGMu(A{7+M0T{;BGNu_?m`Rgc+}W(}bhhTD+4?g$+nGG90|Q3CmJ&Ndy<=;-yI z_J`>%KMo51+>t-O-ybjIIg#U`j)R@S%OQZ_M>nV2nOU8}_4{Zu!D7fNll;lz^waJL z!$e%n>7U&FAI>7Fv>F6B~0i|3=)Q5JAE;XFJO2j3kToIaVB2zXbyQnZE z(dgOLT@lxoEv`uV|8NSqT%(-NkU2_?p{!#>XH_^{)j0wVg^6eHIu4h_h3V%OeI#Pr zr7Ug~y#w@wsI8ru005!^HVDDenc9payEPyOfNEis&uDY}nKb~coxp5i;Qm2oXFh?d zhEbYsVkG~SUDp2=r8+_aE|C2Wu5o>7>`(X6nE;661-5jO>Fb9lO)N+P6fUum#PQ>_ z&cvlS#-p8zIw0g+*uOEpa8ZH@Dq@615NL3*5Wmv@4Tps#yL)dJst*ghA0`Vo6yDyu z8<^*X?O|c*XXKj5LasWp0LW(?Q@BAqX-BeEcff)W*J&hkBZdB{HiUf^%J4OnQziArTgI@?1AXGOO^WKk$=5m16h z$|*KrKs&Y=66IEQ!R7}y;~)8MQ}^V}n49`Rv!v6aIQ=Sum@x zbQx)ZrIQH1US3j|6^C5*)H#l)X!!;?=F{vJM!j8VCeV@68m(2)vKr%Z~PMQw{(FsuMxco}qr z6XO~q*v4c;U0kpq(+|PoDc%-gxSk_bi#8@K;ac=yl3AHC zbIpcH%!HsTcbZNaG^T&|eAKM$(8)p1YAuYBIR_i1CWGx=il3r+YN#J4C4RfJ8R3GE zTPyG#@%2P0j}8n}+8g?x%CHF5rMwOZ3>Zr3;Ew}dNIm&9DO@_mOW-db@*hGToZM3Q zzg0ZqK~hUc{{ZAHK|>N!ry&5c67f8&4fx~5-~J@q*Po=L1(!V4=l4apw@-;!RW6yr zsW}pj>v z0P9qg`B6D%j_ummwQ)Yvv3cv}5v*~Ka^&Y9e?C&VM{-)FzVwqD#vj}~yNWUFRst|Z zQe@3`*5l$4TiD%~%0*$``2fDD3jo`oj339Rs}& zqnj86MGcdHK2dc}96-?60JOsp1xRZYN+7H>us~3+yNF1KQ2K?@I#CGZIU+olVECxx zl*P^}g2s@7k8HbW-fx!9joVcOF~y^9EExUXvMai~XB(NZL?yfhEdD2azK59**j%(| z8M|)W8ll#$I&9A(4;Rg& zWJgx1I#GI+zzPovY&Z;g1cdlyTv$vCWGV%9p(#j{a^MSKz^9@jG#Qz-6rmLq_(DY+ z*oVSU;n>mytVpHjwqn_%mut(AAd6L>+*+kd3g0rwj;XuN;9NEQlHU+MeAoQDm>Y(T zUcV1S%|(%#=!6!lt$oSXo0%(%^NI_=u}k_=4c6~|9ej<~-2{8`39&iJu|#r`oeGfD zC)NOmpcyq)XrJ7&+9NQ`mh>iOtKPM0`rP5Rkj0zjS6v+-Yi2KOb_6U|KXJ(SmZuN( zSlijBPl*@f#kOfbQ#UkPA{WsHNoe|$FcQoIK6{;HpX4#gA0!`1en8$k2kI25u*f82 zExZEX8WogD&H?2x!Wh9*kBoapaD*8d)D>*%G+HVc0BSD?XGS#>56Yrgi`z;QtOdN1 z)x=U7Ehz<<2=-^hVU)&8L!#+Ntnd(Gs5q)1id*FaYXMsziXoN`vKW4gOX5^-w-(zh zR*TF{VDJt~k*pVxGflx7H{UzVDI>k00ROHuummRZcA9Ua;~ zeg1M=R4RJC;z3-7z5-k^i2)08g6@mbJC&Zj3$9|N*TqgeBz+a}y64{XM<)#I9DE>I zAc#gM`sHX|Zd{A9yTdXD6I+zl6L7tQvUWzm=4PaBocH9VW5!&1Wd4n*ZPRDmzG>=| z&6}r8owjwx^lhmd=O3Z_o}70hGe>5Su^x_>N_iw&;^ho75rGs%`~z?(OHNs>CZpAA zG?6=N_!e@B74nVAc+wWK*+Q34%p?qIqRkzkN_rNGP9A{|J4>ha*>zs8-|O*v@A7yI zPMT=Mt$VOgYjfDlY7oYF3pIA1!>n=mJ^rn7jmA_|wzX%kH&n%=z z%%6uN`rl$%q#@FnbsCLOiOf|<{fb)9@Ocrt!)UTk%<^Sc93cnY_Fyl43f!LFoq}$$ zjxBCH_Sx-b{Uswpp%L_dbCcd2tBaZK0V%^Nbt=2oZuZkvgVtt1)Q8Mk>&nh{)t2mx z`Ld!WtIn^^isJl^Am`?AqTa3{_K00=*IzMssda<9uV`M^YR<07Hlscmu}0`ah|feh zzVY?218?%t(4j!&i^zC6Oo$TH+0zg%(?`aEVO^jzBK!e()Wr$i7y zsX{nL7IJJ2jE`r!6y`EfL>lZ>qAwYpj`of??RBC<2AoK0hKE2nC@+M?O!TG%29Nl_ ze^M$UujuXK|K>F$l_3wJ&T8Eu>6b~9x&DW-vq#OC(Vk!9ZD=6L?1abSvUu!)?8>~F zP(fI3a$AdRIeD$6Nn#CW7uVMpA6va*#p=h%C8HN~)K#3q|Y|^eR zR~AK>-_x5el#>a^j|=xGD!MD$D}{%y)Q>DI6CS#V37t|`j2v0PeTyX($KekcnBy4a zXx2gxbpvG;fi^k{zOR=hf58aOgZMK99L!80X-dI$MF(SyYhhd5Rz`>4l5pmSWPbQk z#4ZQpvS8E_j0R<(@--Ps0aG$-Iav2mhR`6tErHW4fGLXuWDxnO2S+DNj5cwshxnhs z0PK%@nexFxL(qb|M>8WdoqNSC*%=*I+<|e@Z$ay#|7Btf5-y0AMkfl9!IQ31!a-2} z0FZ#O7{^k?wCJJ}%iwij#X_Vn6!#52CiD=JX}~xQqCVOqrX%XZx0ZVeFim3P#y+Ik zIJ*yF zd2w=HzqN6C<@D{2OB^jLdoEZwzLU8@WpLZ0_H4zb(PNPXgd5%U%K5^(Z@qQHb=UE) zW!lyfN5b*8X_=YvAg!IvmdqZna8x+{8hGT8_ zR)wlYT{m^zcIU;85nC>*m*wbuptyB~JX6m*f7Wt#!s7JBqec}c%12)CR*ipH%u`Fg z_S8fc7Ybj!hCekmL!_C)(|& zY%zr*;3?1dTV@fR7nUb%`@L~RP-j)jW&$wgNw36RD{xolfbbR3rB_ahCl0_=c zav)S9Zttv)n}qpNrRf4WY*^?0h450PKeo87y2Wl*EA(K&Qz-ZC)+=~s`F3upT%#mQ zD+W%{to-*=h#u*r?j>54(1Y}eCSnR&aXTA%|3_0XwXqD0=St`-CBPd^#5lefabH(R z_Gac`OsG`)<%4uFFz*gXoRA!W1u)5q~4m((-dPA8D<{IR3#ij*}=vm()!ss_8(ruR9F%d*4&kGb~_jH*ie$LHKKHPc(_WG2bX zg!DF<1V}Oo5K1V45Qx;!JA__D7&;0lMG!$SE24;s;@U-w?%I`AS6p>1aaUd4RoB;D zT}U#Q@8`LbgrK29ZNvq?a;IcW*mv@~9S511Xthz~oXu+4 zFp$p6jrK_U*x$o~PTU5sSQT_gXMIY>}9Qzx0p<#K&)cJ){SPDfezTqimnj+mM zoIrj5vx-x_$>tH3^EgE9TtV_2qTGct357-r#1Pucf4|Q>5Y{|Ec>yy-9(-saeD)}0 z8Bs~-6G@Mg%&;Iprx4jMu;>ZX)N?!1%3AVNTIn}h6~74f%t=)pEme~m=`I$iHV#i` zq4eR#Y8Eh9nzSf8E zj^v9#kVD9>L69yyLSoSxFyj&NKv#yS+-1|_e$EF)ST}g->eAPxubJu9l)71?N=z$E zn+EMX{n(BDcWRU?mD-M;?kDg9|A~(ZJGY=dgGd_TKV* zUPiS_qv11u$&00@AEE)04PyFH2U23766Kg{;f_L%E%x4as~g|yh#;nrk2f{(%4+j6%Dy|XN}UTnw*;`7TrGS zSEo1sY0KE{J}9a*;tFI4;8uxo?!?{=Re3;q|Dekg{?pTlY3T(#LG8@;Epi?|IX@p% zFekW+^VgKkziUdLo=e?B&MKi5{E%@x+ejxll`_ zMX5L={cGaKvvJ{DTKQVQ9VuQ7$k)opW`8oNEhJyt5-pEX0!=l^7|k+;RCMXup#~(+ ze}@8odR%~fk&*mPIih+_w)F6pDXZ5#GJ#vyr{hWgwmK$A-~Zv-vrBuc`j?a&dl}*? z;Y6=gOsuYGi0rs_{1fZLqq%;??LQ2i?-+Pq`sc(uURxm+_*1-96Z@o5ASBU-XuD*0 zqv^>A)#y4jq`|Erc$GR5B3Y^1$XP1oGqi2BlMiMTI~I}lG&5gyha?&Beq;pe{EJF7 z^3;KzciE=+(;b!Kq9VK2m*~n&jZJqrlG18(vTM^^cBel!HPe;os~s0TnIi9GcV3g7 zQ=69LaHP{UKfOghiw6ScgYqIo|6oLER}3l%)L0W!60N>*+|TZW$*7Z<5S!pIn5=Q} ziAiyBQ0O>tAW=RlZ?RBI^lV~$^z4r=jE_rjw7}fcB89qsO}uGXT}>bTzwzKT&}8-|qV_y-mZug_yK4wtYYKG8WOznTvzQ06iXEq-ZAZAM>rvNOBSoNAMK z;hpe4&d?=fi_`LG7!Tv|MsD$s5!}%%dUe-;eI-tCjt$oDv($L1l=b*`f z!p#u-YLC+XVAoV3&lE1;ME`^*77zY4H7#8uaQSJ)P&-&B`n8?`g|%xr)0F8+=>-X_ zuFsTeXQ_X{h;ZGEN9Xdw#8V5NoM_Ya%~*2H(t~%-Zd#V3PIdH33ziJcn0Ih?PcJX_ z>HSq&y*H85>$tRBqcLq@u{O!Jv{q$mY)DcY6MMyry{mWU?w`4GP=3?n)7kt-7cWeR zT~Isd)bcqe=B>0(?mfP=zdvCI_gPPmFuC8$HeSMxO@>uKaYg3cG*aw)DD@3&xaG_O zSO>5;Ih+Z-1ki3w2zUCiMpwM-6)UY;kZ&H+3MA0?N@wCOolH=NOn$fU&=qfF zQm1=tmnZC=D+(jie{%7_G(gdpv9NX%Di?+a7(3R9J?r<+1$76lu_$2+EXp3CZ1tx)>pbH-6&lgQC%tBZt*^OlOamX;Y zWXAQaWCe$f`PcOy$y*AKjp@eEc!Gti-R;R|qzh;E{Jp;7W)|K&YyWSV`b@0U;Vd%f zpwXVZaq}4_KNnA$a(~5CDKq}g4-mMz1ew1cgH;}GnMJ-tsR?eY@*FASACOl^GAv3p z)OTPGhS|T%o@^zU9|GcnCIeqgcEQIkh>iz7kCYgr%N2~)sfa>?<&(n2oK{DteOQQE zgp&q|sm_kM&Qx)b=yM4^m+vo$wn*5Pm}uj|Hg+EwgChzo!f~@Sr;&MX3`;nznd4-- z9`;`@hJ~F;Nlq#3%E{ptrY9z*Cq~9cj)wy^HGyz+$&GJX#9kP_qHo_7!=>Ic<#}N{ z=9CMV7jg(&fMRse73eEM8ut^!Puqk7C5I7!c+09$2U5b6Bl{G-KMu&==nDGixVjJ7 zqAcWfu5e1f56GVLkBvRH8B7Eo4-3X zn=LI!+hpGKf%Ln(e~{))dz#K}#y-nG@jcr=?Mzw$_vh-u!s@~?V@4OGrWM?D;sNRH z(_P!M9{3-&Iklj^{%+}aA8umW_X^VFJ(mCBCh3Rw3Mj5Z2dAy?F&EOeO+f!&E@O)G zP76RCQ{-6b98?WXVFgZDR8y3^oSd4BS2V9+H)_&C+AxYnLDP_;!X*R?a08@WnT5vO zW5;3O%OLcOW+gOA5GDk9;-QDCE(Z#eY8Gk>hqD}E!MK_yCvlF(mEXtlPb^t}+*c~? zbn)Jln2c2E_1n#EW8c*^c~;wqS({S~PPg7yT9srgJQ~;M;*mceJ_tFWM0$CtHzp>t z|Ja66NhVdS$tWcDFLQ^k@$$m;8nuTTSv=|L(?xDNE{gY}D{g z&mnd^r&qu75#E8LZZ8|*GfXu7O||NbI8LSFw@j6;fiY?F z2dN$3r`@$P-Vi(7T{|^YEFI}pvFFZ{_b@IqZ>S|dpc7pwMTu4*wpguciSdruob3aW zm%3sA*mRCl83KcE8=2w>#mqLxqCYtpEHH$f} zmJ15bbo7xgUV83trX)|T#|MT!`n#9P)G-#WqCzn0)qP)l^NknF)CPm- zaaRI~K-2dH{?#`0aQX+n0EDa&d_fZM%4Cm6$h#2WAuM{pnsx5bNQZxz*@h;g;ocb< zf?PFVkvezyRynt1bCdL~ya9pzjcuQ9Vc{*GZjbWB8&(yNE(EHunOyNqplaRr#`ZTFw{LG0@*1~uk1nC7&_ZepR2CIg z2HG5s&*|9b-Rl*H0+p2kX{O!&a7HC}dl7mPn1}vkIOnbpgHPq) z_et;X`;rBvGtwaG4E!@^At~n zEV=|`@*uL>(@EDb5rVqO%i--v*E5Nz$i2JTf^$q9v)s8}k)8Jas(RwQBa zL)qqWdhtwn3HVj1K^~gJpw+{Q#X?9pP6zLS;|aVUR1PSwaFf#RShtxrSr8iY{ z+BKZlZx&UBfS=0c&}(>~U&94>YpRv0Dvbj7G8fw$*(j;_MMmhfbW?expq7IJfog@zuC+)hx%PnE!D8%j+SHi zCzR!FO#dCn-@9R$$ZfDE3({>GjSZ^@)M{sn#b&d4V%0Hhgph30XxMZy*@kPNXAxMM zkN&PLUPCJY^rqB#3u?!J}DhkzR1Qur{-A8OD~z)M=Qnt zBjzCG)$1W?cOom6?h%Z*`m|DHtEyP#T^~MuTFnPwo;T@FGrdlF`3UR%)kkXS!jPA_ znAT4+fp_{WD>UwsKK(F@ZExq$5O%Z|`~(FlAIYVD_*nY9<9g{cmhk64SF<_Dh+#wv z+%^i5DD_nt|DQ1L6tYpZTMLPA-95e?g^z9G0JiYhrjCDZdQ5oZ!BCErm=mhZ<{LIW z!)CTsZ9aQ;bK1k~9>Oq}Y&rd+^kx(2&2_L)P-gF5=;4BbM<=1+NaQ!C9SE7sqVPs{ zL_&%yR=~g6!6P}Pl(N$HI%|Am6q`PApmc5I`9%}Uo48`>*iz)on3iskK9E8yXYs## z_SCk+3)qm??6sBR+|^Q&^z1cb-(XW-zoBy6;>feowS&g7ja={czHB;YTQOnQDybZa z?`;K@qn)p_nuP~9KhQ}Vkmu`PvhOcZa&prI(?LH_aceO=)r$+=3{xGkEAnxk1YKuw z5aG#mNX`!BEOx499Nx6Xdf-6o z^Y^Zuv--htuiSUvcfsG^eDI?Oo0qJ8bNQRc?|Vg9)vhibfAh`bON9&T=gw`vtF)4j z4BxeDcn6=El{$ZZ3co|R<#1I;U17n@d0?W6k3NpMdA!U;Qv?=djbG9`|Kj;5j|%$I z6KO@JEig2G;Id7$x#WfPsmnHlwy}_K{A%0c_OI@0PrK`@b#t`8T0C=jHp_T=f5$$< zw)>8AAKG0mdnA<}03atUBVW^!-A_xYPTrm?Zy&(&uDiba>aJzaBYbZ0ulhaq*L@xP zt4ch71kLrM4a#L%LI7>2JZ*${lLQ13%GH*QZ0`Yh?Un(xdjS0ThQWWg9x*8sL7iv8 zk983um{!7@bv>-C*8^vCk77TtFpewEV?>bZhg^^~P?_2(dd>OcAD~5@J${susOJx^ z0=V<%e{{ak9{iaroB=wEK>wfo5CbDqf0{5D!p)1Zfhi-k+n)|5qiALTI2{Ial%%{? zDmpGi)Z%SzFLC?1V{I>uL^`ABzY60VV={g&c|F@WVvcdnD*RS=t~)B1FxygQU&?IQ zxV+u|xOXYi3|@Ks+u=*Qp6m5Swr_a+@eLavdrW%I-?x8Xf76tBKDpoIq+m&Euy#bS zSGqlAuo2vNn#N^_cf=$G10JZQc1x$&s7n55$5iQkG5zJ2rFWJty}8H#n^JN;hLoHX z`sqD6DJeOg+(|hpIrN*Di;(s=(|+_%x^KkND-SIlk#@y1@%+@sHbzU!u1o8s0V1|N zzpx@h>&QyZ$yG5O@(u&TtT!|AI$p^k&lb)1Jo?^JjK5uwbxiORzfy(;hx?P@JUQB^ zSY|XP-`;xkXe%!rZN2^WR@PdPec|2gii&LZKvszRE|kR{$gW`9>D*Deuxas8p``6h zRz*dY*q@fa`W2RVBk`f>pkMD{Jr2|hxoTyBC`To83q)1Oqd_b{yfC)Fh_5RWNLu;1Ip0#Av!Ma1gdE@r!@79a%M76=*cZT%+ z`YoSqV+rS0ojT%QLgJtGOF{1dM|zxT+S z!3nE2Z&@`V_}HySo~$VolB{+^Y@lKOvUj$=&P-!>+g+-XuAkmG;=TH&U%;jH|SFgI`+P`8dF_u3_ zmvq3r+u`L-zZO-SnBt5&0YNaQ<9+;H)y0*Tc&Uy*Fwymos|=p&j!Syv;3=-ezC2iIM8-Uz6ITRz89wPj@`WoqSFDhFiqO zNv%>FyM~2fsp|+?dRsa|Ca4F(7LO42@QTPR?$(YDUI+tnGTiYO?pAq&g=b0%ORl*? zVY3MebFPI0egUGPVf*iMJ}6_?z`$wF4R@e)UBp_M*)Lt zRET+5@AxupZ;)ZJXV-q ztVTvqFvKiI`9`p?vLQeN6&?@an2e3(YA871UDHi(_#kw^keTR5XFzTV>ws<~y6aFC zs$4u5YHXy22sbhX$7#n@Pf;bRrc{psUJCx{@Sl$n^*Xpe>(g?qTD>ktr`K9@()3OX zKsm%1o-Tny?;U$rcN|!~SCf=8GBEBP2lw1t<^gH$EZ6+L^Ici)v;pR~o>L{fGpgd6 z3=<*>LKGqu3UdVlr?zsO70@jf4UaT+9(BChrb5Q>xYQINB%~stUX03ygB}68Dow|+ z)i>O*x@^hy3#Y_?5DLY>U!*jne0PSoyxg0yyF8<`Bz@$FPdw|JZ=!h=S}?dc2vdH6a#b?oX$O#h8f&HB~XrkD{U1~xAACR|bs=vIRd9U6P>BO#gY z58pa1D~VGqt^de{7#d$}#AB;oVojJqCx5+k)9#yIx$ySV2c6OjsWyvwUv3r@@M0Kh z@hf%i?4Prq**;XI`?Pt{iv#D?e!4Ni-=!H($X*C~n^2JC2xq&TuEaS@kc0qp&V3aL z@$W_2_bf_wCqtqm#XB_jSE}2i{D%U5D6QaeN6<{@fp3DFd{LoMgJ%%T3I;*tf{B9< z%D@_EHCU)f%)8R#gfvmalyIH1q!_;T_3x#&?_a;RYT2rR@mYeH9N)XKG#$}Mc~dt& z^Y$|vr{?j@m|oi0J3d(yvf>A>T2>{6k=i~Asesn22{0(d8|7SA6*J0`lgnmQLW||r33e72nPH0u+Vy8msqDTzhd(siII)*BiaTYC zPq0gQhxdGNA#-pjEiE)S^8)d39CYSku|tlnfi_5?A_rwcm4{z)RF?=7N0+wFoWr0n z#TOPVX=E$HPY6rzz1K>5Kj;#n4vcOd_{WAA-HuPToMaiNpsGw zuP%>XO*gG$>*U9@g)i5INQtb=5W<*u%c8M!fCW{k;P(BqO&IXO!Uk75P#n+?kPY+} znUbiKU4`b$_nbzf$|Y%(UmM+gPkQh4p5qk=bRA$2G&aD{t;`tGu~6mJR&yZe}0Uc-oX;o4ax2Tw8+abbF_%jM^aDALO~F3YgTeIm?5y ztG$5&f%g7|`cW5wJ_SSo0cgHJSEU36MbCGAjdfS6-~NAWj4?6yt1CWeP+Zz-utc_9 zu9k>?g|CC9#jy3#(U-4YL3ASX;n!HE(@<57%s1_gJ-?Rxt>oC!d4wMF-_(u19n_fJ zki(rLq>G3}hm8}ot`n)a*nMRqh`-zj_{i&uW@zHId0M8K19!R*Rh)1KEQT#}$8??; zS9+A~J^Ej^5_N-@j|LWLnL10Ipk3O8w(jw9=1uB6F|B0Xx}UTn>3%>nloDdrOQ6%Q zfpw8AGY$^v-hbNfJwHQ4sE1(IbRgZj381okfy|I#x&%#Ozz@R1;2~~;*A#U*q)V1! zHvHp&{Q0AF20ZYU{ps5~OngYql?4Y6o0%Cn7l2S#qp&EFnli(eFl|BddSqWdUG*}>I!WtblG7ZD5 z*mK~)0x1tD_<<0k;w)!g7_u;>D1bnWc0+SP67|ai)Wwun^t7QBj%4Y($KH~T^;`bN zzFM{BhCgjv@yBcA{?p^jOMOxv-76nNfa@La<9|o^qvJd?yc+m$8yb>tK?C9dLJ0yN z3XMHS+Goj0cdo~T4&@KJzk&mBTz5^A9munB|didgX&N!xjvh~Tmr(W(Hl?rr0 z#ABp&84c;7g;OPu{(fnxX9;mO2tr)($uRlxCZsU@3Pz#f(WQYp2Mg@h_d- z5O~*^BunpREq9l8bay=|bT?rj$b5=yck2U*;mSEP3Xw!o9SyA>vuE(K$K=n>qvv;O zG&vwbJBMF6pANq-di=ig|9)P5XQwtE576uyapn9v{J!Y%`_9Yl`qO!qyClf-Y^j{j z(E&_n4uEYi>spF~fo=vRAj`U4j-Oplp_jV_7xi&5apCuv|CIF3$t|Dk&=F;6rf=Fj zAzFx6ATYiXttSX&Wr}{b;}fFyyll0;9DUG) z<8p1!2O3B+4nHpc52T1?xdBm7slTo!l0*sbC$W@`k7LD>=Jn zR@DNa$-fV{r);hE3F&?Ljhlb2jLi3hR-28B+e4SD#38E~9uYn9L@PB#E9Rk7ETg-9 zq6eRdzNO>qpUkWBw;}ydl!xr%&uGF#9FU9aDy+;d%0EQ33|ICfEi?&G3jgOz) zFf3H!-6tWkNHn#6Iu zan!s8s1C{3m)4-|wnCmLC&Us3j8`Z&SSBhYsuPT+BXfXN0P`zX2s0c0fKuG;5Qpha z6?9m-V90Q*NQPcZG5=cpJtAi|EzB+5GIjURL5v?5o2ZOcS&eFS!2mI(f63$+t+8qS zmnWuAKk=o6)v6KS9R*ou&R15gdPVy3*590zCU2j=>J_e_K_hBCnf^d|_THv>W7XsP zIe5L@wq0c(tW~K8hXQ#jX+-Bkuv-7>@h^wX7H85!q;t}judJH1mF<7%_qXE79fJ}Bf5jy^ZiQZ)3N zf*V!`W-OmRxnH`u4FAlHLn+A&^}(>}Uvm8l6@+fsRX^&92osReGUO%dP$3U71PV}E zK2nFt7z-+qT)&cW?d6I(+;kdn#ps=v>-oqZ_r%4s4?iVNgF>p60twx_14*) zS5){A8*<2IO-xFR_jcDe^6}3<}_O5Q|AsXT#4L(ySAtzr_v_aV|D}gwKbR9VGwm9aK+asZPABUsxY{yvv z*J0a1XAgvK{{-7%G%)5goRn>$4%y2EfqWhnG{kUY4|x2ZKq2YKk=!s87HDhxu{Erpq?rG%QXz#}!Yv&wJgpc&)_4V`D|!!o+vs~}u1Q7x z3It-3!PCf}ssgGOkmR&NOJ@Qk8czc8{p}B*H<=vmtqzmv{KM_w%f6M9IN`~l^-pc- z2yc8`e8rfaZhS?2d?O#;@>E-koU@6&K`>AB4~=@oyXCR{bMNm;z(nuw&T{&*W%*My zXK5$`tDL;aLXnoADONPqD|?QL73sM{Wdvt&=?2iD75M%XV^5ejXdVzyP=2Sxr zmm~<|+vg#1=a<@Cr?AYHXuPE0XLTH9TCTeNPjSim5BSgcj%NmPYdB+~Qu+>BCX@^9 zj4?@gT!>QWiLVatyB}eyBa76PNb17LsP|i}V)P}Y`cC8?j>akHD*D5+-ocd20`FNb z=zL!`kd0)MfJ3>G{hB?;-h%-~;^0sy5>gteU7(sk7V~H(X1`Avl($KA@+qU&V6MeA z49F>+;5z>3tP31eh+3+04!T|kcxOlSiGtTaX^#<)0C+XHW<-~Oe^XeP{jLG0a&Ev<36z*n$Lg|I&(VWrEFU=#2jo9Du>`K zPD67Pl>^7bF27lcdgCSPR3-95qs&S`(a;eR_#J#PAq)CY8md-tkP0H-1+ItU*OaPM zl*uUol^Z+qJ*oBrFI7ubjNFg-Lw)2&i2z%tRw0jG6rX*h_F3Wr92=E@N)@Sm);PE} z)g?F_rTVcc*+aJFrRTOS(T|C4=5Q~wUa1Kw#lE6Mv1tS{2)9oA$J&HN*R2@IeW$jn z*!Xa9UV|etGV)vJ*nD8>a-vnOj58#tG`hqjm)@C}8gH@bRDlNMPc;tbQhbS`KF7dw z+Fn|t(b=DsFHUsZ)utiN-hjA4TIq!Ryn^&Kxn(o=TyM)L@|4E_3o9_SZ+#jQRltg2 zd~fGq3uem1MSTax0`@#Z1NB6fUQG0*a3c&FbxcD*t70}wd}^Z8;E7MrY1N5(r}VvM zluJlRw7G|;#_9XH^detUXdL1)Wa#V;lk4JH*C>t0nwXHD)L$Q$>NOSy1}7Av)Wao1g6+*LehE>mffHY95VQTk2|n3lIWL8;WGY?Th0dX*Y2 zfO!`OJjZ)CGv{6RG5cW;fM(29#`uy#XzEp3PN`AFAh)blm|H5uxJ*E4{BoSPM+ zHfwq(v60A);qSG&K}_9PTsTJW6n^vk)ZPA*v!lclu+oy%I!*|-_fsiC!Mb!F&{ zHvkdSEW{d+%*JTUFldrFQ_O3>et~Ng8&+lb2AFy6n8MpNJPzM$;`U9!_$vbdV#askxc zE05z3*EuZ7I<3Z$l%&xbY=$ItOd>v+aWJPH5b$M|d(2*KoJB-t0-&4dlN{rDYnk;&aHqm8Q^A7;_Xu9{>B&)C@V@q$n z+h7RIFd4OM=~}-3*8J)2xFm~UO}chRvZ42u45iUDz0zE{c9DR#yk;Kn_wBM;RBGF% zz8tsd__F24k1t;)`Opy)R$x%+_(A=i6dD@P?6%RPL?ic7pOtZHrNwk}61UN*-}OQ; z|G8WBcEC3g#*m7Q%fOIS>+?l5fSvFVrm>l=I>4=&ODi<$9KAj%4b2kSY%mR6p^FL3 zD-P6hT;C5WN*0$DZJ&a~2>|Z0I(2$oUB8sq?e=~7sScjEC-x1q+~O*qhYcHw{u67n z2*~4bc2b|6#q$C&x|P)?Lq3X+#Ms0$^wR(+8T_u1Jf@M)`wGtt=0dx|E+Y_0Qk9E2 zSf%Bt#D6w!pE6~8Wa*Ucjg8wQ<4WgkyZ$%OF0#^hcl`dADcO9+!1-&3JuxF`^2Ek! zU(AR@(&-b@2Om7WacTelp4?2j3AfWy%~kQ;w?-pW2>WmrWpjbCMTx*ZM`xxYLUg1Ur*5EYYXMjx z*hMhU7YgJ>1BFdU5+?v!RS;S9D9Vy2YcEkCZ~N_4aG@i^O%lDU)fB1;r1my1A$`FTbMMpuU(@|ICPy?%-!#(6 z#)+FYO^j~sJ$J6-MtDsSCreATEc!@i>=Yn-Wh)bSH3qzip5CZ1@C9UUibU=%**EsQ&7?sWlHESQ&cHTK}bD|V2`6XBwv)BmjjjHN(+u4VlkgFk?L^BcmCtpha?@Ph| zN8bkm(j`&27P_QFyd4Zvst2wI(Nviv^g@+{P&H!qg#~i@kBu*DZLz20@^sHgFInSb zV$#!NViGLuYozv&(r~y2r`d0DPBdqTtr=#~s-Sl$cyRLYaaAz4oq)B>HV>9=ztRJ@ zQ8#cT0)^%xdD~fxGki#DfsP^+3Q6BKA8`-Dt!SZ zlERb=IC__W^PT_Na0hZdU`aV2Xe)vi!w3s=G|K1(R7y*2s8OH|NrH{)hzj9NKshYn zNzt=bSJn-ohn+QKJ!=U~q!$u)S5+x{FtSqo8;WiXm#IGH7MHTSl6!L+tTlg^5C3-L2$kF}sK336IXvY@)pY|Z7h)zmTIz7~DRZw~%IeSUEh@9z^rajEAGZs8vFbeUdjnShe=^c$F zgGS*XWJ#C*c%VT}X;~B1Za-x!cjPOV~^4 ziH{>)dxxUy)l6|giz|-s=n%}EUcxuyTq7<*CU+`Y30_Sfvl9 zt8Pzrs~BLRUkOnJuoaQp$%zjXqzG&S6Ixl3^jh!1eVU9& zuH{)=q*70Pa;jQY*c5~O^vd+w#$}DQ=}O_o;sGMB?w1p+;vshr=8LbuA0iz}SjM^~ ztb=&Orj}C=FhH${=v%+Jm=XiYNEry&a0^ThBfXyf z>(lt(D>9@PdsBK&`VLQcZ{_XGaO8+IbjSC1HQph;^W?qKA5YG>=PO=$MRnvpr|9O@ zz*~wxnuUKHnMR)Xm*;62(=Td603V?YTlMWwmRj{fNN){Ks%n?H0RgN7#$4CAW|>i- zgN<}q=V4*k<%=h=@@84zN)N+h=vpM%rar1rhp{4G)&M+K>JcRdT?}dI&}1rfuTK4M zO4N(S1AiY16^@#t%Q2&ogR-n57P|CnQHu+7!N7=yGFTvx8bUhhKA>y??NnR@ncx-d z5ko~f*GNoHTZ_#4G^SS=Bs*=gzuBj*ooZ))qn$`aRc>xouCROJjr%t5yK!RmlIgPr z%TS9jd-{^3L(nA5DD>NJhJV3nZuM9q7E;Ww@L>NER{D*cy?}8$CSa#syv>m zWrKA)-+c5*mB*uc^3gYU>aKdUr;allIwu7Kx`4yd9o?G z(6uLqk#lCz+_};ssr_=5Atmm?h}gr#%f}*plh!}<-R8~TJ+wYalh>dA`$nR_MEft7onoo}H(#f-?1*zj(cxMDOJ4*+@NU;S2t! z-{9Os4|N!Jy_}Kp@~$iU)4=~_iBqraPfC@Cut5Hc&UF1e?##UF(XIaTO8lfF74F$n zNImL`?_h*=dobwXk4Q=o4#_!czsI0fAd?iX zC@_o9#dnddy+pL-V29`iXdqPPkfAXtkqjNQ(vmKLWf+%`TXy%RpThV+J86L%RRp#X zoy1s_v=%@m47R+Ohj8Q$<>ge#i&R$ZM_w6-#oGB=`DlUPpux$?0#QA>vb3tt?34ue z^qu+z%BI>#c=UYfwV}JF=|ts@$wfJXgfPG%Cg$}+WMrM|K3cctrb_SnD@g2(>y^eH zPV4mp9d=)rUa97)a>8p0hlwm)kW!qlx@r0kg{9Ka*xcHt<)c~p;F+z{cCpDD?E`46 zQTr&Aji3|xKw?*rVpx`wv5tfKmYRtghgt^B0+~aO5+U)l>&ou7K>Qf;Z17Q*%uo0d zB%Y8upW`Ps9>@to48Lba+qh(Q0B`SI1KdIXk1j!&HcNvu^WAxIYa>je34d`$pGf@^`4QTY`tL|f8FiIz;0siMG!tc|X;FCr^q9f6u`FK39z5-I2W zGH22JQG;1sW-(L*uWe7Gb}ua&kmHkH3Gd1eh_2-Wd|KE7&54_8=N>Ts{lMJF^oAYw zdMEedz#)d9C#On#NLyQQNr8>cdUd?r>nI3mnhinTd_i3kNUt)y6hfHK+!rb`XLcy8 z^|}FB+--rHb)J0b-JJ63oHyR6&QgyIWDGKcVs`dDSsqN2@$t};Fbq3+!ZPOVW>)AU z&<8;!Bt^NC!dKgaF-b;YxeH>%$|KqdyGQ3{v9P{uVH($WMN_SW zgf7ybA|KT@-LsP2nGqQ^eV@9rsaDxCG4dOKsG|}AS0=NzFqsc^v|w93D4Pq9PcIQe zTHtjKsG5YaoNv;zvREXjU>Ma(MM-|gKW=|XIsywr?dhAEYTYaE32&P=VwStM>0%3; zc4R%TFY?8^Q*&&|J~vV`8nSwqq#KPbN#03S?s%W-s6Hp*d0Bxak4f3rumBjWpjkdY z1wG3Pvd0klNdQw!YdN5n?}Q{le7-W3C-3xBOn=d_YwfX#218sw#xg>hWYVVsUPC;L zT~RuS+c3n7eC*X>tF1Hi;xg6RiRMjX>o(fzX4y8@U9-h7VU_AyZP1aIk{>tcKxu&_ z_OH+Pm1*u=zeiK%%M0_L7<+4As{|gLom7>o3zR zi$B0uTvAM~VS7povmNZi1lPpv+WPskMoM?G`$o=MI#zqb#Mo3xp~^J5bh?}8lsEaL z&4tQvo-Z4-1J|>d>|>L@GHebsbv*~h!tpRocdm`z9s2pG!KNv1xM5b z8oA!V5#hu0KHvt}$EvnXdT-eRX?JL3lnl9*@3`Xn+9jA>v4Ji5SG9x^M0-XT5z#LuC5g1AjLkm|MFk(F{VBU>~sj zNl(x)WMHtM7PP7A0f*NfuhwtYR^{MuvnJGDslG5Xv*HC%rJB%7hN^VvZ4G(oz5%=`mjy18Z9Idcz;ACk402(i>I z4i2WdjvcPZXQOQKIaS+Crc6ts^bu{Rxmcsc2CVE^j@ZbG0gH0Jf^olQMKv5~pdTHCG*8;MB7-JsBf`?)9kAvn&##OnR=MDl*tWXA0yo6sz zxLzq($%%cS5Cm`)MIjJG5yNCn9)|oi@Y;FDqTdFuoj>TUKy``JTLr@~rqSxR##mU+ z(`x%Fo90Y5v&3xEYc<2MzR{-nK&$2T!iO5$F1>|sU9Puuye;3HWzjD;SghKP3cXHi zj^Tz%V-bvbZ{(pEvsP>1pN%nFBNt*5RH+&SeVM6Bs8A=4r3R7By`ymm1QHHes~AO< z>*D80ff5Y@0gVSzLUbN5mp?Ck`=jScHSi*T_}d$A{FV*vGNbgYcQ$B^oau_eN)K(2--ihb z97gvLas)}S<?ck0Bl{6I@z&V}9WabcIzcen5?o&E(5a0>yaP-o zozbKY=#9K7D=;ei=HEWY$KXMuRq-4eO8EtXMw zfzu-|kQD_dY{c!Ib_BR|)x7X?AA6;)T(sC!Qj7 zsa4e?x@Dgdg+_3y{2CV2@cy7v1Lsi{<64Q>MH;#06ODr;H*0-X`j~6xnj?+aXRVU^ zS>|b!!dxpUR_TO%868fhi#ji(+dgSzVd~?uyejLB$dAPj(up@Y;fv!8`ZZ$E9|U48 zBKxoGy4>r?L-1uoOQZB9bEc17FZJfL*b7o`WC3vED050*rjO-^UZs+cB1+BK@C+`Y z8^gGzioJka{|AqI29Lvy4S>-5X{RJz^#{<`rJ-%Cuq#BfYz_dD(|83cLe7F+y|T-y z3aoeHTMLSz&_nmc7Uc_&4XzGcBX1!(oSixC(c9@>)F*#KD=7 zHjq3zAes}YPlIBKd_p{O@^fwn9BG1ZTMr5wgTsTt;T`_P&5QA0*s!>E#FE9$9RrRn zU3Tow&yNWkk1bnz3_BekOaJrCb#Jd-`}TFu@b^j*;tZtaZ{Iq8?EZ7yNa;IdK}AXh zwoYK{v&uCK4@nmeZ~3A&ca*N)UHj#h!_tLA3pM3gY{7nZ+n-w54O~L>^+Ar_UOb83 zxp*;?%g`df_!#^A*s;%#N$G4IGp;?~c7Cm(TeNWep|_VWee>WXcs}DWJ_BAW2!-nl zZ+Y@I>B6l|(@L&&toBY@d@EDm_T()%K7DZ$`pir?;2pv|tHHN`zp%m$?`kX%k|mP? za?XKA5aldafi0F1k>M001GOU0F?k*3AmthPA-Mqa2NFUKM0{UqyYvIo0=Y*k9e8}x zrpGt2EWMyl&-O2UX)x2dTrtUGlKZ_ReV;rAo5@T!=+!0u>~vhBP0I^;L|fIMrqc0u zd3~NxUK+O?8K%$RNk5!=Yp{8H>LsxT)FJ6+G)LqtOZ3HoNIFBE%H1< zE>)G1l4M~<#V(e}-Nh0A%b9#`gygz^qCUQT;^v7HH?u-*TAyUCZ|%kv2?@!4(zK5B zeswn$-k9%jXdGpZXO;}ZQsZzuQ?zSzzx07;rGK71i-bUHdP1GTa}Q6N82P~#E5@l~ z)6*=LI5F0i-6tzxD7rDP^8rhTMjv^$$Pmct1FyB1v-C9fMMr4mJ@>5STd>5JC4N4v zd|V8}kB@x#WC2n}V+4RVq(DeDmpO8cjPEH6-O8lOaoazWo_*j!>DkY>PY7|(=BBcn zy#w+g`#&u`otl$BAdT(!h~e>-k&6#XEuU}O_BjhZ$f-gT+TZmMz+(OYkMs&F_6*1` zOp(@-PKTi^2SEd7QJ)hLSp-uBq8Jf;kqSgGkKF()Jq0qWLG6j&77*=G2QIi}`H(?8 z007oP90IAg7V`$`rVB^@7QAHOV%aRdD$i%jwCy6oil9oBb} ze8)J}x1ZfJ-@ULRw*O=nI=|0azQl80|Cx$CVHnsap1sD{j`GNNo>|;u`H@Ro;BfLR zZ+oR+=@`+cF5nV-r}pXCJ-v(_&hWEO0|U4MmdoYjRR6vIJNtwAoGMMpSUy)?AXR&i z`k24y%QwKElgkozwTEh=e638QwXo?d0av@X2gM`F6Cuv5T=3ddXbL1vfNQWy)_;)S zaEhN2%n^+v+9k_NMpAGD36>WUQ!WNyki6b8bAuJ8)F;pYK-_|KZ*x>&V467c@aW0R zT*1ijk9gwZeJKUt4JK)pZ{0DOmyW4cZQePFyJ0q;7$@la4Eb=A34DW+nFbAc@qQL- z)nkxwi;pG`(CWngh6S7_LD0w9Y{ObN8#z6$GY+hH?E!y`&b#Q=a{6N zN8J7J$o|GToYy7jlhXN`Pc|C?BY@Wq>UZvb<}k%5tuZl8hg`T$tkN$i(da`pA8m}` zs0#W)f018~Vq7i|x8W*NmP|8P=iKU0q!2m|Bg>lChtE}2b2oi1{gdr) z(9Mua+D@NtJFQf3Yqoyl*WA6Aow)seX?|qRO*bb=WuA*{{Rd1JJRm(IeHf|RV&E2S zVihZtxZ`vijVr`aLXY&aY)x=0fC&o08i-!Ri_;i_M<`J^mD8_;F|eF$2Z*Z2Jm`0^ za##n^uh3smc0plva0Vvu+oaE=0rPuXst?Z6>6Yj-zFt003L;_x`E0@@3UE#g1_BKN z3@gEV19lb(NCgH!a~fL3Ky>B&G;EOG`26wb4ohFnthq)IuBn;HY=@sazFK3F>&GE^%L86W$bF3xPI@#`Ky@v z=5JX4(~lBw%2sw7qdEnX#WQ9wEY`kV~?+5Xugcq6Z@qbhxwP>8nsJQe{Xm)*G&5Y`~qv!8k{px_ii!V$W zv-FlVkL65d7r1xDcW>JL2X1Uh-rnaYj=ue$Tk4iE)zap^_psSNj6iw|3!BWA#|NiY zEj#%rd$4Y5b?!ZjwzaPvGqG;aM_XU#hTM4eEUFlte^g=2KSn~={;@|`)T(LkG6r^Q z-2&K>XD6IdDXjX7FhGLpz)T4!HNj&O+cm!dqG2$kVCnb!N%+1RecHlxQ|9S@w z!AmJbmtlch`4-uNN#$~2Ui>S{PuE^nRjIJHCD|x;D#;HY0mTb$(2I zRYL!>$Bw-;+}A6lkI^}E^WD=QpthBB*NCfSeMzyd0#g)Kb%*h^E`_6ao)Q-wDGEGr|*4vly)8^c~?~OP2_AX8|njjPUbhCF48aR92 zz|g|YjSp=dyldx+FYOG(a%$xNwI|!n`~sJ&<2*}Wo3mie>UU~KX6Gbpbh>!GMm2Xv z_~tDe5-cEn`i=M8dGLCja&dVmRMFJ5ch;ChwK|dU;|8pqIkmW?B#06Vyw%H%l1r>D zs}fC|(V)^+R+*A4VpXNtl`v$*!Z{;rCrqdvHQS>~Fq;ym^=Eb5_QqM~_U?Pbq$?;? z^Stt=Su?5!)(&crru7@V^})$6?Ap0AkisGTxmt7@xf4d`LMbU@v^8f!?Z`Pz>opP&nU^)=EmtwLTRWs^_e8tTs}dcNkG3}MjAG6F#<;oAT~La7Py=kUbw~=dogF= zk6>!R?E_ZLz-MrnDde~Z!t4Vql z(daPh%QxKm@rsq-JbZk5ids-=^wuK!!%a9$=mQrZ8XzaOWm@MM6teH${P-|f8 zfd8*@Zb8mkX>)?tXVCvSeYn-CGx%0+-@R#ec}c@{t9DK+u&0bw+WQvuwMg%0jazqm z=JY$JRK`UbtE&c&b{YE2UQpRrsZ6q(f+PFomycgQv6sdOggjw+{)1!E-!je1uj^&d zTC;C;s5Cr)iK5A3InI=)RK>7+lB)_bbh=jWFq=*1=rcB5nOAqy_|ZEj4(^qx;nr8W z1DwM(YB>C537(sJ|+!H_AXVCJJHXb@sXt6LfNtIPb%1p9ZbU)Irl#?Mx z6N7^g60wY~F2QKoMIj?SwuNvT94%UjcDBk_^w<;?LyIo^uQU?*ZR}h|ku{=TsXeya zEEIakg?{`b`Jq>|j}bB{wGnx+b(%M2>kDQA2FIme#QyBz*VA45C}v@_Y0*|f7>*$= zR5LDw+)xS;RRvgDcQf#c%i9djOjl{OaM4iKjGLnuM&1$>EkCKVL9YMst2Y#hK$!m( zoqfU&&PDDM-pe3s6vurzlAe&!NEAngqW`mY7)ufOXU;@p%%6Tb8g<^af98y)!~Nei z%`FJbzslp}fPZ?t)cXIey=;)9(t#QRtXO#U6KE2eiW*2>{NFW@=#&)5IwQ44Tjm26 zZL0Rh|E^iMzLEl<%kF4<<7x6^BfbBN#voZb%JU|5(h(B=z^!zyFhzHF|wFm&D|vAM^8g7eqt!jo!d*7tt6EN z-tEP>_@g{Wc`42!s)FjSkf)nCf*;0M=v3cdrlwF~Q-3HVmtN(YTJ5gH^tKlHy`gAS zsvkvRi7q0ERk?*Y~*0% zpw?hDW0%7&H=CR7Zja?c?Tt{jw?xRvssDZBeh77ebca8FZsFLHv6-T-Z;WVtM*qlOdHA`-l z8Y|YS627=%xBY}#$tf&Wy;=z*9jg+|dRxe*hJw+Gx!tBlWB&9Ae@UUWwt-3K88$@l z?DXA99&$q-qR15^_;PZH?bHExWmM@}L!&KAM(an#~5!gihJ+=mfgm_V7GDdeYo}Vf0lzJb?@D4xxYjU z@EV=bA$knn_`JM+{&A6;PBH(z_folKI^Lt)IW%|u7{OHN)Hags1bP`TPe2O?)G}D+ zG{E~oAnmFU>8S(0Vjm>)auK>PctA4L%f+r*voEFD(vdfB+Bh~LHs|2AnWY2DUSreV ze3Ol&3Rl;>AhqRJipE%h7ZFq&!>RJ@y<%OuBad7*8F7#FsByIREWG2Z>ziI3QqVYl zWW{`+QoZ9VX8B6maSDy0exRR04LT#31S8l&b--DYGbsHUraZ9m>-%QRxbJKEJ8A@l z_%HN8CA`%2M5Td2ZDw&uBY`ys@e3woc}d$qF7-!FOYib4Bd1xqaFn*W5z>2f6fMaV zqb{{5?-xUI9J-Q0;m`YcXv$Q65-5Vj4yT3Mkv4JAB07}!Yo)W&uRptSYF5Lbddq@g zu_tnFtDn5gndJyp7S5WX)~_iItzvcUeA`#j6lo+=HM1(F96Hs0OZp9J&4wM)Cu1)D z>R0tU;@R~&HGSi#9#sK(kte@m~gm za=r8h-AnyCs(S`w0bj8C&ii4faRyjLFq+#4(I0o)6VD>%5N2!S9TzNsgO0FD|(zW^%wCkPf)x*s0X2LHS!YHx9LF z^@CZk5O{!84i_Ay3wHFG=NN? zx=)vNGr92N8wqO<*?OV|8N`ptMi`KD@@4SChU^rfpX;9%s z71kh+VDS{59tlUCd@6#4pa+BZfimy?A>Z%XcVTz^o);Hx`f}(W7D~6j@+;~6x7V$E zoB4iqo-LL_+#}0iDF5csE=&2NNOp1jy4(GY+uhkQ+Uy?|t-4|Ng}n=3+*7}L{&n}X ztb1E}AJhYnc!#T&nj;b{_Fd+6>H9CGWz7shBqizS+ivhFt@wt7)zXPa5cDv=8KD?v zAUZQ~U*ymPer($#j|;ck_C>y86Qr1qd)Rb<>TbNH%?lmlQg=RALW16?A z>@=F7uPMaEvi%gq(q2&P;&AWfd+;noWBots-UB?2>gpTcduL{QlXkVMu2oz0w%T14 z+p?PFZp*z}bycit6*r0n#x`K8u^pO?3B83-LJh<~0)&JTLJK6s7*a?=38`Rf{Qb_% z$d(Psn|$x{J^$x#YiI7OB27?qt;@uqGejpF5p{d=MAqr#Fzo z?`}uB*XQ%5JEEZL?tI;0b69aK116lB$mtxvY7i#=08co^1YX{Nz5*jdCAX%rRGdvp z$_5ZJ9SV*l=%tNup#*+LI{2$tXbJOxvjwhIS(SbYm>+mlx+V*J3=vB-(VAW(+9w|| z8chc0iQ6*^olz;?6kk*`c#p~sP(EUhZuV8?7ba#!yS$0{1+ntAo=aDf(9X(BJzcQ{ z`H5avbXH!P-Crlb$6gpEfKsaKCXEZ|9-~wio z|G~t^U@y+by1(J@gz)|^FfLh;NvOoRL<>d-!fV7;1n-cHT)?{~f>;W$p;hfptB&!) zW!m0_jAsBV>Tp`&1wT^D=FIXdEUFCWsVHJQDO7;IuRdgO8ggQ-)|5oEciZdd>^c_i zZS>?+=`)SFx(+{>avNN3Q#-#hVig#l`5EGo!7+>Cr7r zx67O3b;aAFdwZj8@$psB?2#!=F$G1jiGsNzdFHHheztAz*2D$g>U_`K{cr3aSa8LQ zpWSucN1n$%lArrs+>=}Hzbe%hH9fwI@viu)3|ssa^>XYBX}0L9_*~A0}Nt$Vj3PmAMLZh(kbpaUoX5thz%5kMGrcDrx!qhctbY6 z(sNm%sAzoQoDjym1aGoY`sMi#Z{Pm#`5zD8kh=HdzQ@jKh3R5bV!@IPi}MqV-o)Ol z?BN5^1>yDUW+ysEuIS9kS+nbfZChTvV6{IvFPtC6^{)6}Mq#4cu`)BWzAe}6uRnjq zyz|!0E>3fqxoy?xl#t9>$Kv>c ze1D)I&1NWDJ#@+X1y}88sR%CK&|O+MJ1@y>j`oLFgq<$NsupC%`oqOjlHw}D)nyIg z**Gj9_*Lm9RexP~_UQrff-tKUDQ3)aMdwRVN~dkWk!W~!r@6y$WoJH(ou%5%nu!rK znJJ`&*-3f5>giV1Kc7U)sq!{BZ-O@cDQ$S2uZlSf!3knc5BWI3_KCPoM4}P;IpdiZ zovG8#4zcX7_U`>keg{|fDYZwL`zohO2})--{P=hFeswC>0+pZj_0K>XPt&jD(eP_M z2|S>x^P}g)>d7UrBmb_izScjd$4rw)`d7VEruN1uV2DjsWa2fC zo2fUS1e1YS4TPa4!Z&^Jfewg4(^-ze{=Ep4(rnVR13VEPpHOxn3x6cW0XDr*2#QD% zv!#+^9@iDl zG7dXPu9QXM)47l51nHU?#}4CL@dw=s_1^4*Oh*phrN>Kgna9sxcTvQ3+3Gt~dG$M1 zU*?Kjw9Yc401;##{f>ee0`=hdhQg^+3;6*APaNeCsXiQ^F6O|Lc3fID!ssNqS?Q|N z;TXi{i0Skqho_0}%I)m&l>?M$V5K~h-I!la;c~!#DsaiKK_>{XGY=10=>i>o!Q}={ zoXC`0sz97`f{OH0A%YTxkK{TXqWO%|Goe%wa-|TJApE*ot`_8S1I%SsvoeR-ES5|0 z^5csPu}7U|ldwQW=mQ*9A@pOqAtjqxO<^S^o4LpkcT|0UDn#X&h#iHa^M4+VJ*l(W z?MGwf$FRIPS^2~r4@YB}`i{+_ck+u9cdM1=fT-)iIM z!+raO%l7X((ZXJ10sMb${GjgSI*2O#02$aI5avIvOfCMLT<4ft#7SVdK5`vi^JT9sjd@DX z1^Jy`Hp)hO!8Lec{3Cqh#JZvKk#eA4q&vkq(l|;wr(Ut<=OXSGota=O$`oWRYHx7J z(KT;g*EoLo6X$)PS|q%{cKoQz2MDx@KIJ~%tiAaurJE-x$>+%_69x>AxTC)si}%O7 zqb1y))S}S=l1?}|Q$H>}j+t(TyrLIAzu*rBQfOta90(K^Y%gGpN+|5@5@Ju> z2%{ho_6px8KQjLL^K#&MV?Zj77;unrqY$e+8ilG8Ccep*7sG-lO!_tBH}ZDx_)ht! zF?qJ}OND>n$*aJH%5OW0IYFl`=p}3f(wU+|o&~b2EI?NGa2Sl;1GrNl-_n$wS_b+G z{YBiiXf}5EurQ-*&+adq*~)+JyFkuXY#WTVt&+zd+xAMOYo4p}m2Hp7}X9wAD z*}>2Gk)z{ptj*x8X>N043uEUUJ@Vvj9orAS-@THtmEG?j+}?59ljKkyD-Xem>C|{m z?6X|p{^w~r-_VmF&t|kQJ@o_j%Y#dK0}+^5dp$%Pu(DJMf0I^XLV8>{0na#J$oH^i zB$hkgEM!@YK6%&cugkl9Myu5*zGK9e?QwYn-}5V6jxDb`o?W$kd6oE1)pEXZY)p4@ z`*xYEAL!KZiCZbhN!>m7U``s3XQK>p{ec4q+^4gVB}rP3v1tVCr_icIqS^Fck0W(R z>p-lM&P^$XvqFhy`K*WsCqN$qznC!e#D%f0@;$GmWvnu1WmQF1hVo5fe&fjSHFK|n z`;buL{GZB;=WSdvrLu5t7N*fNEcEfEi<2e0&Bp4wV>q7m`cq2^QT^T@Y-KK&jJ_E8hqf+-`xG-=A}!$aLSm( zW8tO)AENO-@f~DMgX~Up;_C{TLGFaS`WRyYGzDav02P<@7c0tk2^;+7stiST=o7TYoY!Yg|)iz zteU9K-fgeQADva9T>K3?DWYNOfxn4YM14F9{fkv+VjtzA$!W+^IbgV#0qpgVQBjQj zQU5zwCS+TQ1>lCLr?RU6PXPf?J<_@LQocAXM=#`82KLjuC9IEC*Iw#de7dc_8s3lvS;ec{O=7#* zyU)0B`#U#Y64`b2D{C(uN?`dbZcdhJS0=sbHAKt5i7BcJ{NBy(>Y`%4dV1QPk-cB- z`~JQ?EBmf~8DB+v#tC|#By?9}UYt76RtaeaqX3X(QxCh9BW{=rQ0!We3<>QBNr+bw zGT}Zr!%F79DyU`B`gV%G6$UjI#fQnVQu4Gszc0zFM8zbOrX+>(R|Lzml1fcZi?P=% z8n%6S!F!*|CqB8SqvM`Wn5f*@)n^mMjVMelmK_T;Rwly*OH0f`2Q>_W(x z182D4#S{OPeRTp!_b77?n?ynJQO@YNfow2h>XGCRq&U+3S#TW-$e{;6^N?szh<#^l z?b@+5?6RqKcKK?^ga`)9Hgxbl@2#{Z~h(BIaQ@v(Qb0~}L2nm_eWFh50i1D(2-ou2Ik>+r4 zP4D=#%w>Pa?vj61W{#Hs7UQz?d>oL8{9drd-uF=@@(9aD<7bgqhz|1aZ}c?%Al^aV7m)?$YO znIZ|y9TJxFV*w_{4J-k|OBgJBV2?q_pQKR1v#0lvy94afhMB~|=)bZ$xPY^WNra4` zd%)P!dq9mN3Jf46296b!2yD1fjuM4!xPf=agR(HfUS@`OeQcUdZuXT-1Yxv{UPSU5c?MK6^2{UzlI(?P>t4ri5w{D*da|pTIgmV@wv|=fNseH+=qH22wy9jj(oy zGjj&*C}o7y)eK~X^M%nSo580U-lTB&S10Df|I({Ot)Ko&`oJuS(KCRud2;~jd5^gHdM4ME6yqmwv?$}RH#jwV~F>Z zEY%c4CLZYy1CLh{Y3Ff0IEsqUfJ=5Nq~51D;1RWJa=4IZFpgt4Hj37@l~L zRbg{0f|YdO- z{><*kjyi0ydw#YrYX8=hg#klKL(w@`WltBS;_Rh!3q!-58S%mcr&7eH7bL~0X+&d2 z+2mBw|E4NtPh{y-7q8~9i9I(|o@z|VN()`6-MJFWqSND}QleP0uw zr(p6IGH_?e#SZD+VHtG5>pV!cfas$M0=uWUUG&&RUF35FK}>%5Bgx3hPRl6u9@s!I zeA5RGe^N?%M$o(FhVf^QjXz~gv)*a7>Z@`2IDTgB1#4clrST&gxbM}#pM6N~?dUFr|q~~c%f~`fdMZP#pPJ<_@esS8$-VJ*jJ*zxc{nTh?;*Jw% zsOf=9h0L4uF6`0AflkF)83}?I^ymjt^YQ>12ni5h7GxE@QF@Vhzvvt~we*5YRXPn+ z7Jw~R73m@{3YYreyV2mKWI!4G_fVShW@UBvMrF(>5)-X%Gj~=yUHl7&QSWK2PPyYT zhu)lI^se9WVDs*qvQ~usx3bj2LLUxz8$)>>$pCo<_Tg7E&UvaIrVuyHlZ41E%RMQs zZQ`r3NhuC*rTmXe@|P?qf;@rMJfDT;uNl9?U}J*Qw9e?t*pss6fos>_adBv@yDpJ= zvjVgHsoB%lZEDUnae@8qSnsiCFL#;bYg^@SX9yKlHp349Lk#Ea+aX^!4L;&_qjyLY z7Jsx0M#&l=kg-1iX@0Irvuhh6ZmD2d7*;GfV*%25AW<8#Yo7 zM%wQRo;CpUl3)?^mz29pdv>7*DN(o#1`ekC65gLyvNzi@OJC#zGxD%0t0L@YqFkL* z0n5`_?1}Mz%jT7mz^kI^0jB+v5^qo_JTv_>>7O*5XT< zlW+ysGheiDn?rOITgx`^oV}sy_tSDqGyfQ8PfML23ys*XVq!AW=eqxVu_Goeb3xQI z5o2;Jlt{~SvdV>~=zZB0cNb2T+kAOqxvxAM@`k>tIaxtgEmh~F7ffAmo}QUez?(B! zq3t~HqE!D&=Vfv~{2oXwWkHiHU1ZQArIGz(OQT7z#vXtXu*Lh zNw7+fr4VU$;|RXmO@;9TSW{6lni!#G=Gd)`=dsz(dKj4wnI7j)oa}DH7CD? zD2vN{Zna!*sLT=m`Kie^r2_o>th`uuuEl!kk#&M)sYzZ@T&B zo8G?WAA3`(suTZy=iQ%ta`&qFwv5)fN90%9ndH0t&e!i>Gb8QrxA|Mgrks=?pSxvy zrfdDxap5VMOXKsCoy#h__w`Mi5ABFaeEfJ_4!FJbpn8EBvj7qk#3|-BTuoTzUAuS7LTxpIY;^$AI-Wkr(@P~uWLq4c4kz2O>nb6I46|* z`PbHj34Yi@MQ%>{CK_tmI^&x`+|e-8vPinV#M+~1)t47m2#TZC15=G|ifk2bV2@2^ zhlwXWbsb5DtfH(;w>8@$8l|X=UCUmW7X?`qYqmKi9d8WPyF8b0qr+(}wWn9-&&k7;+(w6wJ?3birdl`x|+Bn)*X{%^*Hpd zOOqr|p-0MfnUd3!@n>{rOCEOoY(5y%Ilvd(h&}Eaj6aYvfh!HAGWCg808%E#0YNbq zM|8r3J`?o^NtO}nQ9&I&M%qf07bG!7!&X}3t~V<2F|u%An8;%CvaJdn>|Fl* z{Ah4cKuftncqnjiDL2}kwo+SqjS2@f>9(NF;V`mGneL3q03fihtRbms4G5+O7i0hk z{PX?uxHC=#0*jr1pooCLtO9|_l_z)v%UN@Q5pP(rbxl~$E~(@XfII^t;8hIVZZMZ5 zW&b4TiI#-$Rv}~xf}tRWIa-G)AbHEGL=e>`-HgH7kjEpKOTCVUnnq($mwb=>>$N{G zTHtidd~C_ic~5}mHd*xgXC1z=V|!)Y#fx_}=31Hl(vOd@z8_1jicmv&(B8rQr88TC zwdZcG)$0n^Hq6c~(no(%m^9s=uTOc=esAb}XR^VNFxQu9OY!5x-6G$SWQbkGSz=*Y z6!?4kGS&|-LncRB!R*2Z#QDwVTvfAp^PE)mOhvJu+5nn)J?uY|Y#W&T!0(fOX<20k zSS>mIBd$Jh`=lSxBi!Ge@e6XuR??gyl#mhaQslCsi$I62%0znvQ3_Q4C%yiY4_w)AJynX_(SpIo&5*5 zuJg_7z=a^?c*2NfST3Ty zz>Dfnxxv(EbQW#MfJD_4gfzpdeL5n#uusA2qbxPb8wDd{K1!rtFG6~qwzPC?tlX$q zDS#zAi;`p0M_W5(5y!HGy^2DuQyXY0=OFh8(<=?~2ust-)6&W>%$b^haXOXYX&Kj+P>7RPj5xFva7d9tqzzkXkGd18re@WLx*MI|?dk0md8 zaPL5yO>U@et)AXKosZ7_R_pw$%8J)?gjQuh_*I;{jCt#(R?45Q5vSy71(czXqVm zr~>{W*Xs7^bnq95Nhd+b*g%>|I9Ds=XpaNl7$9mbK)DJnAfIGt22BE}FF>f}bV>9+R zYUiLRxWa%uP0bQ>ah)|(A*NZf>WdiUZ1~}Lzr8*&=uNbgms_JU;zKDlP7IeqOX(CG znyKuaPHzJs{0+hYRI(Qx=wTTc8{!p!ys!&Ej^K0q!5knV1}Rw#R0#&CH+%(^2aB;P zrlDcmZT(VHabsm;V6DFYwrvd!F;zy(_)nQ(u|oc06b)U*PRr^q**)(hghsoz=xf9KeN1C;PJI6N2f z$gI9<$wKo8m@G_z9t|(c0LQ}>g^$fFq*Rm|XxyL)&`jd7VF!W!LMG}lSZ$J?%`yt+ zygSYpvvL>C$z&{Z&VqcuwB?R0G&a+iU|Ii$G(UevEMu`V@?jjBms#SUUp-@u{Fcy| z+d$C`xsAfxKdubf4Wu@xnE9X%&N+uY4;NbV=Tez-=ND$=9Xqx%hYytEi_

5q!RY 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 + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/FontAwesome/fonts/fontawesome-webfont.ttf b/docs/nightly/guide/en/FontAwesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..35acda2fa1196aad98c2adf4378a7611dd713aa3 GIT binary patch literal 165548 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 z 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 d0mRO}xo^G_%I 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 SdSQM28?+M|D(2r_;{O0|uQ74} literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/FontAwesome/fonts/fontawesome-webfont.woff2 b/docs/nightly/guide/en/FontAwesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4d13fc60404b91e398a37200c4a77b645cfd9586 GIT binary patch literal 77160 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/__unused/event_javascript.rs b/docs/nightly/guide/en/__unused/event_javascript.rs new file mode 100644 index 000000000..d80501b46 --- /dev/null +++ b/docs/nightly/guide/en/__unused/event_javascript.rs @@ -0,0 +1,26 @@ + +## JavaScript Handlers + +Instead of passing a closure, you can also pass a string to event handlers – this lets you use JavaScript (if your renderer can execute JavaScript): + +```rust +{{#include ../../../examples/event_javascript.rs:rsx}} +``` + + +#![allow(non_snake_case)] +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch(App); +} + +fn App(cx: Scope) -> Element { + cx.render(rsx! { + // ANCHOR: rsx + div { + onclick: "alert('hello world')", + } + // ANCHOR_END: rsx + }) +} diff --git a/docs/nightly/guide/en/ace.js b/docs/nightly/guide/en/ace.js new file mode 100644 index 000000000..e8435a507 --- /dev/null +++ b/docs/nightly/guide/en/ace.js @@ -0,0 +1,43 @@ +/* +Copyright (c) 2010, Ajax.org B.V. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Ajax.org B.V. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +(function(){function o(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]);if(!i.define||!i.define.packaged)t.original=i.define,i.define=t,i.define.packaged=!0;if(!i.require||!i.require.packaged)r.original=i.require,i.require=r,i.require.packaged=!0}var ACE_NAMESPACE = "ace",e=function(){return this}();!e&&typeof window!="undefined"&&(e=window);if(!ACE_NAMESPACE&&typeof requirejs!="undefined")return;var t=function(e,n,r){if(typeof e!="string"){t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace());return}arguments.length==2&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)};t.modules={},t.payloads={};var n=function(e,t,n){if(typeof t=="string"){var i=s(e,t);if(i!=undefined)return n&&n(),i}else if(Object.prototype.toString.call(t)==="[object Array]"){var o=[];for(var u=0,a=t.length;u1&&u(t,"")>-1&&(a=RegExp(this.source,r.replace.call(o(this),"g","")),r.replace.call(e.slice(t.index),a,function(){for(var e=1;et.index&&this.lastIndex--}return t},s||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t})}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+ta)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n=0?parseFloat((i.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]):parseFloat((i.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=i.match(/ Gecko\/\d+/),t.isOpera=window.opera&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(i.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(i.split(" Chrome/")[1])||undefined,t.isEdge=parseFloat(i.split(" Edge/")[1])||undefined,t.isAIR=i.indexOf("AdobeAIR")>=0,t.isIPad=i.indexOf("iPad")>=0,t.isAndroid=i.indexOf("Android")>=0,t.isChromeOS=i.indexOf(" CrOS ")>=0,t.isIOS=/iPad|iPhone|iPod/.test(i)&&!window.MSStream,t.isIOS&&(t.isMac=!0),t.isMobile=t.isIPad||t.isAndroid}),ace.define("ace/lib/dom",["require","exports","module","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("./useragent"),i="http://www.w3.org/1999/xhtml";t.buildDom=function o(e,t,n){if(typeof e=="string"&&e){var r=document.createTextNode(e);return t&&t.appendChild(r),r}if(!Array.isArray(e))return e;if(typeof e[0]!="string"||!e[0]){var i=[];for(var s=0;s=1.5:!0;if(typeof document!="undefined"){var s=document.createElement("div");t.HI_DPI&&s.style.transform!==undefined&&(t.HAS_CSS_TRANSFORMS=!0),!r.isEdge&&typeof s.style.animationName!="undefined"&&(t.HAS_CSS_ANIMATION=!0),s=null}t.HAS_CSS_TRANSFORMS?t.translate=function(e,t,n){e.style.transform="translate("+Math.round(t)+"px, "+Math.round(n)+"px)"}:t.translate=function(e,t,n){e.style.top=Math.round(n)+"px",e.style.left=Math.round(t)+"px"}}),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/keys",["require","exports","module","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./oop"),i=function(){var e={MODIFIER_KEYS:{16:"Shift",17:"Ctrl",18:"Alt",224:"Meta"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,"super":8,meta:8,command:8,cmd:8},FUNCTION_KEYS:{8:"Backspace",9:"Tab",13:"Return",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9","-13":"NumpadEnter",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock"},PRINTABLE_KEYS:{32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",111:"/",106:"*"}},t,n;for(n in e.FUNCTION_KEYS)t=e.FUNCTION_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);for(n in e.PRINTABLE_KEYS)t=e.PRINTABLE_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);return r.mixin(e,e.MODIFIER_KEYS),r.mixin(e,e.PRINTABLE_KEYS),r.mixin(e,e.FUNCTION_KEYS),e.enter=e["return"],e.escape=e.esc,e.del=e["delete"],e[173]="-",function(){var t=["cmd","ctrl","alt","shift"];for(var n=Math.pow(2,t.length);n--;)e.KEY_MODS[n]=t.filter(function(t){return n&e.KEY_MODS[t]}).join("-")+"-"}(),e.KEY_MODS[0]="",e.KEY_MODS[-1]="input-",e}();r.mixin(t,i),t.keyCodeToString=function(e){var t=i[e];return typeof t!="string"&&(t=String.fromCharCode(e)),t.toLowerCase()}}),ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function a(e,t,n){var a=u(t);if(!i.isMac&&s){t.getModifierState&&(t.getModifierState("OS")||t.getModifierState("Win"))&&(a|=8);if(s.altGr){if((3&a)==3)return;s.altGr=0}if(n===18||n===17){var f="location"in t?t.location:t.keyLocation;if(n===17&&f===1)s[n]==1&&(o=t.timeStamp);else if(n===18&&a===3&&f===2){var l=t.timeStamp-o;l<50&&(s.altGr=!0)}}}n in r.MODIFIER_KEYS&&(n=-1),a&8&&n>=91&&n<=93&&(n=-1);if(!a&&n===13){var f="location"in t?t.location:t.keyLocation;if(f===3){e(t,a,-n);if(t.defaultPrevented)return}}if(i.isChromeOS&&a&8){e(t,a,n);if(t.defaultPrevented)return;a&=-9}return!!a||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,a,n):!1}function f(){s=Object.create(null)}var r=e("./keys"),i=e("./useragent"),s=null,o=0;t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n.call(e,window.event)};n._wrapper=r,e.attachEvent("on"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent("on"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},t.capture=function(e,n,r){function i(e){n&&n(e),r&&r(e),t.removeListener(document,"mousemove",n,!0),t.removeListener(document,"mouseup",i,!0),t.removeListener(document,"dragstart",i,!0)}return t.addListener(document,"mousemove",n,!0),t.addListener(document,"mouseup",i,!0),t.addListener(document,"dragstart",i,!0),i},t.addTouchMoveListener=function(e,n){var r,i;t.addListener(e,"touchstart",function(e){var t=e.touches,n=t[0];r=n.clientX,i=n.clientY}),t.addListener(e,"touchmove",function(e){var t=e.touches;if(t.length>1)return;var s=t[0];e.wheelX=r-s.clientX,e.wheelY=i-s.clientY,r=s.clientX,i=s.clientY,n(e)})},t.addMouseWheelListener=function(e,n){"onmousewheel"in e?t.addListener(e,"mousewheel",function(e){var t=8;e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/t,e.wheelY=-e.wheelDeltaY/t):(e.wheelX=0,e.wheelY=-e.wheelDelta/t),n(e)}):"onwheel"in e?t.addListener(e,"wheel",function(e){var t=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*t||0,e.wheelY=e.deltaY*t||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=(e.deltaX||0)*5,e.wheelY=(e.deltaY||0)*5}n(e)}):t.addListener(e,"DOMMouseScroll",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),n(e)})},t.addMultiMouseDownListener=function(e,n,r,s){function c(e){t.getButton(e)!==0?o=0:e.detail>1?(o++,o>4&&(o=1)):o=1;if(i.isIE){var c=Math.abs(e.clientX-u)>5||Math.abs(e.clientY-a)>5;if(!f||c)o=1;f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),o==1&&(u=e.clientX,a=e.clientY)}e._clicks=o,r[s]("mousedown",e);if(o>4)o=0;else if(o>1)return r[s](l[o],e)}function h(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),r[s]("mousedown",e),r[s](l[o],e)}var o=0,u,a,f,l={2:"dblclick",3:"tripleclick",4:"quadclick"};Array.isArray(e)||(e=[e]),e.forEach(function(e){t.addListener(e,"mousedown",c),i.isOldIE&&t.addListener(e,"dblclick",h)})};var u=!i.isMac||!i.isOpera||"KeyboardEvent"in window?function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)}:function(e){return 0|(e.metaKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.ctrlKey?8:0)};t.getModifierString=function(e){return r.KEY_MODS[u(e)]},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var o=null;r(e,"keydown",function(e){o=e.keyCode}),r(e,"keypress",function(e){return a(n,e,o)})}else{var u=null;r(e,"keydown",function(e){s[e.keyCode]=(s[e.keyCode]||0)+1;var t=a(n,e,e.keyCode);return u=e.defaultPrevented,t}),r(e,"keypress",function(e){u&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),u=null)}),r(e,"keyup",function(e){s[e.keyCode]=null}),s||(f(),r(window,"focus",f))}};if(typeof window=="object"&&window.postMessage&&!i.isOldIE){var l=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+l++,i=function(s){s.data==r&&(t.stopPropagation(s),t.removeListener(n,"message",i),e())};t.addListener(n,"message",i),n.postMessage(r,"*")}}t.$idleBlocked=!1,t.onIdle=function(e,n){return setTimeout(function r(){t.$idleBlocked?setTimeout(r,100):e()},n)},t.$idleBlockId=null,t.blockIdle=function(e){t.$idleBlockId&&clearTimeout(t.$idleBlockId),t.$idleBlocked=!0,t.$idleBlockId=setTimeout(function(){t.$idleBlocked=!1},e||100)},t.nextFrame=typeof window=="object"&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?tthis.end.column?1:0:ethis.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.rowt)var r={row:t+1,column:0};else if(this.start.row0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n63,l=400,c=e("../lib/keys"),h=c.KEY_MODS,p=i.isIOS,d=p?/\s/:/\n/,v=function(e,t){function W(){x=!0,n.blur(),n.focus(),x=!1}function V(e){e.keyCode==27&&n.value.lengthC&&T[s]=="\n")o=c.end;else if(rC&&T.slice(0,s).split("\n").length>2)o=c.down;else if(s>C&&T[s-1]==" ")o=c.right,u=h.option;else if(s>C||s==C&&C!=N&&r==s)o=c.right;r!==s&&(u|=h.shift),o&&(t.onCommandKey(null,u,o),N=r,C=s,A(""))};document.addEventListener("selectionchange",s),t.on("destroy",function(){document.removeEventListener("selectionchange",s)})}var n=s.createElement("textarea");n.className="ace_text-input",n.setAttribute("wrap","off"),n.setAttribute("autocorrect","off"),n.setAttribute("autocapitalize","off"),n.setAttribute("spellcheck",!1),n.style.opacity="0",e.insertBefore(n,e.firstChild);var v=!1,m=!1,g=!1,y=!1,b="",w=!0,E=!1;i.isMobile||(n.style.fontSize="1px");var S=!1,x=!1,T="",N=0,C=0;try{var k=document.activeElement===n}catch(L){}r.addListener(n,"blur",function(e){if(x)return;t.onBlur(e),k=!1}),r.addListener(n,"focus",function(e){if(x)return;k=!0;if(i.isEdge)try{if(!document.hasFocus())return}catch(e){}t.onFocus(e),i.isEdge?setTimeout(A):A()}),this.$focusScroll=!1,this.focus=function(){if(b||f||this.$focusScroll=="browser")return n.focus({preventScroll:!0});var e=n.style.top;n.style.position="fixed",n.style.top="0px";try{var t=n.getBoundingClientRect().top!=0}catch(r){return}var i=[];if(t){var s=n.parentElement;while(s&&s.nodeType==1)i.push(s),s.setAttribute("ace_nocontext",!0),!s.parentElement&&s.getRootNode?s=s.getRootNode().host:s=s.parentElement}n.focus({preventScroll:!0}),t&&i.forEach(function(e){e.removeAttribute("ace_nocontext")}),setTimeout(function(){n.style.position="",n.style.top=="0px"&&(n.style.top=e)},0)},this.blur=function(){n.blur()},this.isFocused=function(){return k},t.on("beforeEndOperation",function(){if(t.curOp&&t.curOp.command.name=="insertstring")return;g&&(T=n.value="",z()),A()});var A=p?function(e){if(!k||v&&!e||y)return;e||(e="");var r="\n ab"+e+"cde fg\n";r!=n.value&&(n.value=T=r);var i=4,s=4+(e.length||(t.selection.isEmpty()?0:1));(N!=i||C!=s)&&n.setSelectionRange(i,s),N=i,C=s}:function(){if(g||y)return;if(!k&&!D)return;g=!0;var e=t.selection,r=e.getRange(),i=e.cursor.row,s=r.start.column,o=r.end.column,u=t.session.getLine(i);if(r.start.row!=i){var a=t.session.getLine(i-1);s=r.start.rowi+1?f.length:o,o+=u.length+1,u=u+"\n"+f}u.length>l&&(s=T.length&&e.value===T&&T&&e.selectionEnd!==C},M=function(e){if(g)return;v?v=!1:O(n)&&(t.selectAll(),A())},_=null;this.setInputHandler=function(e){_=e},this.getInputHandler=function(){return _};var D=!1,P=function(e,r){D&&(D=!1);if(m)return A(),e&&t.onPaste(e),m=!1,"";var i=n.selectionStart,s=n.selectionEnd,o=N,u=T.length-C,a=e,f=e.length-i,l=e.length-s,c=0;while(o>0&&T[c]==e[c])c++,o--;a=a.slice(c),c=1;while(u>0&&T.length-c>N-1&&T[T.length-c]==e[e.length-c])c++,u--;return f-=c-1,l-=c-1,a=a.slice(0,a.length-c+1),!r&&f==a.length&&!o&&!u&&!l?"":(y=!0,a&&!o&&!u&&!f&&!l||S?t.onTextInput(a):t.onTextInput(a,{extendLeft:o,extendRight:u,restoreStart:f,restoreEnd:l}),y=!1,T=e,N=i,C=s,a)},H=function(e){if(g)return U();var t=n.value,r=P(t,!0);(t.length>l+100||d.test(r))&&A()},B=function(e,t,n){var r=e.clipboardData||window.clipboardData;if(!r||u)return;var i=a||n?"Text":"text/plain";try{return t?r.setData(i,t)!==!1:r.getData(i)}catch(e){if(!n)return B(e,t,!0)}},j=function(e,i){var s=t.getCopyText();if(!s)return r.preventDefault(e);B(e,s)?(p&&(A(s),v=s,setTimeout(function(){v=!1},10)),i?t.onCut():t.onCopy(),r.preventDefault(e)):(v=!0,n.value=s,n.select(),setTimeout(function(){v=!1,A(),i?t.onCut():t.onCopy()}))},F=function(e){j(e,!0)},I=function(e){j(e,!1)},q=function(e){var s=B(e);typeof s=="string"?(s&&t.onPaste(s,e),i.isIE&&setTimeout(A),r.preventDefault(e)):(n.value="",m=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,"select",M),r.addListener(n,"input",H),r.addListener(n,"cut",F),r.addListener(n,"copy",I),r.addListener(n,"paste",q),(!("oncut"in n)||!("oncopy"in n)||!("onpaste"in n))&&r.addListener(e,"keydown",function(e){if(i.isMac&&!e.metaKey||!e.ctrlKey)return;switch(e.keyCode){case 67:I(e);break;case 86:q(e);break;case 88:F(e)}});var R=function(e){if(g||!t.onCompositionStart||t.$readOnly)return;g={};if(S)return;setTimeout(U,0),t.on("mousedown",W);var r=t.getSelectionRange();r.end.row=r.start.row,r.end.column=r.start.column,g.markerRange=r,g.selectionStart=N,t.onCompositionStart(g),g.useTextareaForIME?(n.value="",T="",N=0,C=0):(n.msGetInputContext&&(g.context=n.msGetInputContext()),n.getInputContext&&(g.context=n.getInputContext()))},U=function(){if(!g||!t.onCompositionUpdate||t.$readOnly)return;if(S)return W();if(g.useTextareaForIME)t.onCompositionUpdate(n.value);else{var e=n.value;P(e),g.markerRange&&(g.context&&(g.markerRange.start.column=g.selectionStart=g.context.compositionStartOffset),g.markerRange.end.column=g.markerRange.start.column+C-g.selectionStart)}},z=function(e){if(!t.onCompositionEnd||t.$readOnly)return;g=!1,t.onCompositionEnd(),t.off("mousedown",W),e&&H()},X=o.delayedCall(U,50).schedule.bind(null,null);r.addListener(n,"compositionstart",R),r.addListener(n,"compositionupdate",U),r.addListener(n,"keyup",V),r.addListener(n,"keydown",X),r.addListener(n,"compositionend",z),this.getElement=function(){return n},this.setCommandMode=function(e){S=e,n.readOnly=!1},this.setReadOnly=function(e){S||(n.readOnly=e)},this.setCopyWithEmptySelection=function(e){E=e},this.onContextMenu=function(e){D=!0,A(),t._emit("nativecontextmenu",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,o){b||(b=n.style.cssText),n.style.cssText=(o?"z-index:100000;":"")+(i.isIE?"opacity:0.1;":"")+"text-indent: -"+(N+C)*t.renderer.characterWidth*.5+"px;";var u=t.container.getBoundingClientRect(),a=s.computedStyle(t.container),f=u.top+(parseInt(a.borderTopWidth)||0),l=u.left+(parseInt(u.borderLeftWidth)||0),c=u.bottom-f-n.clientHeight-2,h=function(e){n.style.left=e.clientX-l-2+"px",n.style.top=Math.min(e.clientY-f-2,c)+"px"};h(e);if(e.type!="mousedown")return;t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),clearTimeout($),i.isWin&&r.capture(t.container,h,J)},this.onContextMenuClose=J;var $,K=function(e){t.textInput.onContextMenu(e),J()};r.addListener(n,"mouseup",K),r.addListener(n,"mousedown",function(e){e.preventDefault(),J()}),r.addListener(t.renderer.scroller,"contextmenu",K),r.addListener(n,"contextmenu",K),p&&Q(e,t,n)};t.TextInput=v}),ace.define("ace/mouse/default_handlers",["require","exports","module","ace/lib/useragent"],function(e,t,n){"use strict";function o(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler("mousedown",this.onMouseDown.bind(e)),t.setDefaultHandler("dblclick",this.onDoubleClick.bind(e)),t.setDefaultHandler("tripleclick",this.onTripleClick.bind(e)),t.setDefaultHandler("quadclick",this.onQuadClick.bind(e)),t.setDefaultHandler("mousewheel",this.onMouseWheel.bind(e)),t.setDefaultHandler("touchmove",this.onTouchMove.bind(e));var n=["select","startSelect","selectEnd","selectAllEnd","selectByWordsEnd","selectByLinesEnd","dragWait","dragWaitEnd","focusWait"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,"getLineRange"),e.selectByWords=this.extendSelectionBy.bind(e,"getWordRange")}function u(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function a(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else if(e.start.row==e.end.row-1&&!e.start.column&&!e.end.column)var n=t.column-4;else var n=2*t.row-e.start.row-e.end.row;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}var r=e("../lib/useragent"),i=0,s=550;(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var i=this.editor,s=e.getButton();if(s!==0){var o=i.getSelectionRange(),u=o.isEmpty();(u||s==1)&&i.selection.moveToPosition(n),s==2&&(i.textInput.onContextMenu(e.domEvent),r.isMozilla||e.preventDefault());return}this.mousedownEvent.time=Date.now();if(t&&!i.isFocused()){i.focus();if(this.$focusTimeout&&!this.$clickSelection&&!i.inMultiSelectMode){this.setState("focusWait"),this.captureMouse(e);return}}return this.captureMouse(e),this.startSelect(n,e.domEvent._clicks>1),e.preventDefault()},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;if(!this.mousedownEvent)return;this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle("ace_selecting"),this.setState("select")},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=a(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=a(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle("ace_selecting"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>i||t-this.mousedownEvent.time>this.$focusTimeout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState("select")):(i=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=this.editor;this.$lastScroll||(this.$lastScroll={t:0,vx:0,vy:0,allowed:0});var n=this.$lastScroll,r=e.domEvent.timeStamp,i=r-n.t,o=i?e.wheelX/i:n.vx,u=i?e.wheelY/i:n.vy;i=1&&t.renderer.isScrollableBy(e.wheelX*e.speed,0)&&(f=!0),a<=1&&t.renderer.isScrollableBy(0,e.wheelY*e.speed)&&(f=!0);if(f)n.allowed=r;else if(r-n.allowedt.session.documentToScreenRow(l.row,l.column))return c()}if(f==s)return;f=s.text.join("
"),i.setHtml(f),i.show(),t._signal("showGutterTooltip",i),t.on("mousewheel",c);if(e.$tooltipFollowsMouse)h(u);else{var p=u.domEvent.target,d=p.getBoundingClientRect(),v=i.getElement().style;v.left=d.right+"px",v.top=d.bottom+"px"}}function c(){o&&(o=clearTimeout(o)),f&&(i.hide(),f=null,t._signal("hideGutterTooltip",i),t.removeEventListener("mousewheel",c))}function h(e){i.setPosition(e.x,e.y)}var t=e.editor,n=t.renderer.$gutterLayer,i=new a(t.container);e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused()||r.getButton()!=0)return;var i=n.getRegion(r);if(i=="foldWidgets")return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.setState("selectByLines"),e.captureMouse(r),r.preventDefault()});var o,u,f;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();f&&e.$tooltipFollowsMouse&&h(t),u=t;if(o)return;o=setTimeout(function(){o=null,u&&!e.isMousePressed?l():c()},50)}),s.addListener(t.renderer.$gutter,"mouseout",function(e){u=null;if(!f||o)return;o=setTimeout(function(){o=null,c()},50)}),t.on("changeSession",c)}function a(e){o.call(this,e)}var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/event"),o=e("../tooltip").Tooltip;i.inherits(a,o),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),s=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+s>r&&(t-=20+s),o.prototype.setPosition.call(this,e,t)}}.call(a.prototype),t.GutterHandler=u}),ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),ace.define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||e.column!=n.column;if(!S||i||s)t.moveCursorToPosition(e),S=r,x={x:p,y:d};else{var o=l(x.x,x.y,p,d);o>a?S=null:r-S>=u&&(t.renderer.scrollCursorIntoView(),S=null)}}function N(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,s=t.renderer.layerConfig.characterWidth,u=t.renderer.scroller.getBoundingClientRect(),a={x:{left:p-u.left,right:u.right-p},y:{top:d-u.top,bottom:u.bottom-d}},f=Math.min(a.x.left,a.x.right),l=Math.min(a.y.top,a.y.bottom),c={row:e.row,column:e.column};f/s<=2&&(c.column+=a.x.left=o&&t.renderer.scrollCursorIntoView(c):E=r:E=null}function C(){var e=g;g=t.renderer.screenToTextCoordinates(p,d),T(g,e),N(g,e)}function k(){m=t.selection.toOrientedRange(),h=t.session.addMarker(m,"ace_selection",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(v),C(),v=setInterval(C,20),y=0,i.addListener(document,"mousemove",O)}function L(){clearInterval(v),t.session.removeMarker(h),h=null,t.selection.fromOrientedRange(m),t.isFocused()&&!w&&t.renderer.$cursorLayer.setBlinking(!t.getReadOnly()),m=null,g=null,y=0,E=null,S=null,i.removeListener(document,"mousemove",O)}function O(){A==null&&(A=setTimeout(function(){A!=null&&h&&L()},20))}function M(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return e=="text/plain"||e=="Text"})}function _(e){var t=["copy","copymove","all","uninitialized"],n=["move","copymove","linkmove","all","uninitialized"],r=s.isMac?e.altKey:e.ctrlKey,i="uninitialized";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var o="none";return r&&t.indexOf(i)>=0?o="copy":n.indexOf(i)>=0?o="move":t.indexOf(i)>=0&&(o="copy"),o}var t=e.editor,n=r.createElement("img");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",s.isOpera&&(n.style.cssText="width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;");var f=["dragWait","dragWaitEnd","startDrag","dragReadyEnd","onMouseDrag"];f.forEach(function(t){e[t]=this[t]},this),t.addEventListener("mousedown",this.onMouseDown.bind(e));var c=t.container,h,p,d,v,m,g,y=0,b,w,E,S,x;this.onDragStart=function(e){if(this.cancelDrag||!c.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}m=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?"copy":"copyMove",s.isOpera&&(t.container.appendChild(n),n.scrollTop=0),i.setDragImage&&i.setDragImage(n,0,0),s.isOpera&&t.container.removeChild(n),i.clearData(),i.setData("Text",t.session.getTextRange()),w=!0,this.setState("drag")},this.onDragEnd=function(e){c.draggable=!1,w=!1,this.setState(null);if(!t.getReadOnly()){var n=e.dataTransfer.dropEffect;!b&&n=="move"&&t.session.remove(t.getSelectionRange()),t.renderer.$cursorLayer.setBlinking(!0)}this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle("")},this.onDragEnter=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||k(),y++,e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragOver=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||(k(),y++),A!==null&&(A=null),e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragLeave=function(e){y--;if(y<=0&&h)return L(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(!g)return;var n=e.dataTransfer;if(w)switch(b){case"move":m.contains(g.row,g.column)?m={start:g,end:g}:m=t.moveText(m,g);break;case"copy":m=t.moveText(m,g,!0)}else{var r=n.getData("Text");m={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return L(),i.preventDefault(e)},i.addListener(c,"dragstart",this.onDragStart.bind(e)),i.addListener(c,"dragend",this.onDragEnd.bind(e)),i.addListener(c,"dragenter",this.onDragEnter.bind(e)),i.addListener(c,"dragover",this.onDragOver.bind(e)),i.addListener(c,"dragleave",this.onDragLeave.bind(e)),i.addListener(c,"drop",this.onDrop.bind(e));var A=null}function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=200,u=200,a=5;(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var n=s.isWin?"default":"move";e.renderer.setCursorStyle(n),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;if(s.isIE&&this.state=="dragReady"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(this.state==="dragWait"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(!this.$dragEnabled)return;this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(i===1&&r===0&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var o=e.domEvent.target||e.domEvent.srcElement;"unselectable"in o&&(o.unselectable="on");if(t.getDragDelay()){if(s.isWebKit){this.cancelDrag=!0;var u=t.container;u.draggable=!0}this.setState("dragWait")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}).call(f.prototype),t.DragdropHandler=f}),ace.define("ace/lib/net",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("./dom");t.get=function(e,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.onreadystatechange=function(){n.readyState===4&&t(n.responseText)},n.send(null)},t.loadScript=function(e,t){var n=r.getDocumentHead(),i=document.createElement("script");i.src=e,n.appendChild(i),i.onload=i.onreadystatechange=function(e,n){if(n||!i.readyState||i.readyState=="loaded"||i.readyState=="complete")i=i.onload=i.onreadystatechange=null,n||t()}},t.qualifyURL=function(e){var t=document.createElement("a");return t.href=e,t.href}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o1&&(i=n[n.length-2]);var o=a[t+"Path"];return o==null?o=a.basePath:r=="/"&&(t=r=""),o&&o.slice(-1)!="/"&&(o+="/"),o+t+r+i+this.get("suffix")},t.setModuleUrl=function(e,t){return a.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,o;Array.isArray(n)&&(o=n[0],n=n[1]);try{i=e(n)}catch(u){}if(i&&!t.$loading[n])return r&&r(i);t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r);if(t.$loading[n].length>1)return;var a=function(){e([n],function(e){t._emit("load.module",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get("packaged"))return a();s.loadScript(t.moduleUrl(n,o),a),f()};var f=function(){!a.basePath&&!a.workerPath&&!a.modePath&&!a.themePath&&!Object.keys(a.$moduleUrls).length&&(console.error("Unable to infer path to ace from script src,","use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes","or with webpack use ace/webpack-resolver"),f=function(){})};t.init=l}),ace.define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop_handler").DragdropHandler,f=e("../config"),l=function(e){var t=this;this.editor=e,new s(this),new o(this),new a(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},u=e.renderer.getMouseEventTarget();r.addListener(u,"click",this.onMouseEvent.bind(this,"click")),r.addListener(u,"mousemove",this.onMouseMove.bind(this,"mousemove")),r.addMultiMouseDownListener([u,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,"onMouseEvent"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel")),r.addTouchMoveListener(e.container,this.onTouchMove.bind(this,"touchmove"));var f=e.renderer.$gutter;r.addListener(f,"mousedown",this.onMouseEvent.bind(this,"guttermousedown")),r.addListener(f,"click",this.onMouseEvent.bind(this,"gutterclick")),r.addListener(f,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick")),r.addListener(f,"mousemove",this.onMouseEvent.bind(this,"guttermousemove")),r.addListener(u,"mousedown",n),r.addListener(f,"mousedown",n),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,"mousedown",n),r.addListener(e.renderer.scrollBarH.element,"mousedown",n)),e.on("mousemove",function(n){if(t.state||t.$dragDelay||!t.$dragEnabled)return;var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),s=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?s.setCursorStyle("default"):s.setCursorStyle("")})};(function(){this.onMouseEvent=function(e,t){this.editor._emit(e,new u(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.onTouchMove=function(e,t){var n=new u(t,this.editor);n.speed=1,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor,s=this.editor.renderer;s.$keepTextAreaAtCursor&&(s.$keepTextAreaAtCursor=null);var o=this,a=function(e){if(!e)return;if(i.isWebKit&&!e.which&&o.releaseMouse)return o.releaseMouse();o.x=e.clientX,o.y=e.clientY,t&&t(e),o.mouseEvent=new u(e,o.editor),o.$mouseMoved=!0},f=function(e){n.off("beforeEndOperation",c),clearInterval(h),l(),o[o.state+"End"]&&o[o.state+"End"](e),o.state="",s.$keepTextAreaAtCursor==null&&(s.$keepTextAreaAtCursor=!0,s.$moveTextAreaToCursor()),o.isMousePressed=!1,o.$onCaptureMouseMove=o.releaseMouse=null,e&&o.onMouseEvent("mouseup",e),n.endOperation()},l=function(){o[o.state]&&o[o.state](),o.$mouseMoved=!1};if(i.isOldIE&&e.domEvent.type=="dblclick")return setTimeout(function(){f(e)});var c=function(e){if(!o.releaseMouse)return;n.curOp.command.name&&n.curOp.selectionChanged&&(o[o.state+"End"]&&o[o.state+"End"](),o.state="",o.releaseMouse())};n.on("beforeEndOperation",c),n.startOperation({command:{name:"mouse"}}),o.$onCaptureMouseMove=a,o.releaseMouse=r.capture(this.editor.container,a,f);var h=setInterval(l,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){if(t&&t.domEvent&&t.domEvent.type!="contextmenu")return;this.editor.off("nativecontextmenu",e),t&&t.domEvent&&r.stopEvent(t.domEvent)}.bind(this);setTimeout(e,10),this.editor.on("nativecontextmenu",e)}}).call(l.prototype),f.defineOptions(l.prototype,"mouseHandler",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimeout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=l}),ace.define("ace/mouse/fold_handler",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";function i(e){e.on("click",function(t){var n=t.getDocumentPosition(),i=e.session,s=i.getFoldAt(n.row,n.column,1);s&&(t.getAccelKey()?i.removeFold(s):i.expandFold(s),t.stop());var o=t.domEvent&&t.domEvent.target;o&&r.hasCssClass(o,"ace_inline_button")&&r.hasCssClass(o,"ace_toggle_wrap")&&(i.setOption("wrap",!0),e.renderer.scrollCursorIntoView())}),e.on("gutterclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.getParentFoldRangeData(r,!0),o=s.range||s.firstRange;if(o){r=o.start.row;var u=i.getFoldAt(r,i.getLine(r).length,1);u?i.removeFold(u):(i.addFold("...",o),e.renderer.scrollCursorIntoView({row:o.start.row,column:0}))}t.stop()}})}var r=e("../lib/dom");t.FoldHandler=i}),ace.define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){"use strict";var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]==e)return;while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;typeof e=="function"&&!e.handleKeyboard&&(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||""}).filter(Boolean).join(" ")},this.$callKeyboardHandlers=function(e,t,n,r){var s,o=!1,u=this.$editor.commands;for(var a=this.$handlers.length;a--;){s=this.$handlers[a].handleKeyboard(this.$data,e,t,n,r);if(!s||!s.command)continue;s.command=="null"?o=!0:o=u.exec(s.command,this.$editor,s.args,r),o&&r&&e!=-1&&s.passEvent!=1&&s.command.passEvent!=1&&i.stopEvent(r);if(o)break}return!o&&e==-1&&(s={command:"insertstring"},o=u.exec("insertstring",this.$editor,t)),o&&this.$editor._signal&&this.$editor._signal("keyboardActivity",s),o},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){this.$callKeyboardHandlers(-1,e)}}).call(s.prototype),t.KeyBinding=s}),ace.define("ace/lib/bidiutil",["require","exports","module"],function(e,t,n){"use strict";function F(e,t,n,r){var i=s?d:p,c=null,h=null,v=null,m=0,g=null,y=null,b=-1,w=null,E=null,T=[];if(!r)for(w=0,r=[];w0)if(g==16){for(w=b;w-1){for(w=b;w=0;C--){if(r[C]!=N)break;t[C]=s}}}function I(e,t,n){if(o=e){u=i+1;while(u=e)u++;for(a=i,l=u-1;a=t.length||(o=n[r-1])!=b&&o!=w||(c=t[r+1])!=b&&c!=w)return E;return u&&(c=w),c==o?c:E;case k:o=r>0?n[r-1]:S;if(o==b&&r+10&&n[r-1]==b)return b;if(u)return E;p=r+1,h=t.length;while(p=1425&&d<=2303||d==64286;o=t[p];if(v&&(o==y||o==T))return y}if(r<1||(o=t[r-1])==S)return E;return n[r-1];case S:return u=!1,f=!0,s;case x:return l=!0,E;case O:case M:case D:case P:case _:u=!1;case H:return E}}function R(e){var t=e.charCodeAt(0),n=t>>8;return n==0?t>191?g:B[t]:n==5?/[\u0591-\u05f4]/.test(e)?y:g:n==6?/[\u0610-\u061a\u064b-\u065f\u06d6-\u06e4\u06e7-\u06ed]/.test(e)?A:/[\u0660-\u0669\u066b-\u066c]/.test(e)?w:t==1642?L:/[\u06f0-\u06f9]/.test(e)?b:T:n==32&&t<=8287?j[t&255]:n==254?t>=65136?T:E:E}function U(e){return e>="\u064b"&&e<="\u0655"}var r=["\u0621","\u0641"],i=["\u063a","\u064a"],s=0,o=0,u=!1,a=!1,f=!1,l=!1,c=!1,h=!1,p=[[0,3,0,1,0,0,0],[0,3,0,1,2,2,0],[0,3,0,17,2,0,1],[0,3,5,5,4,1,0],[0,3,21,21,4,0,1],[0,3,5,5,4,2,0]],d=[[2,0,1,1,0,1,0],[2,0,1,1,0,2,0],[2,0,2,1,3,2,0],[2,0,2,33,3,1,1]],v=0,m=1,g=0,y=1,b=2,w=3,E=4,S=5,x=6,T=7,N=8,C=9,k=10,L=11,A=12,O=13,M=14,_=15,D=16,P=17,H=18,B=[H,H,H,H,H,H,H,H,H,x,S,x,N,S,H,H,H,H,H,H,H,H,H,H,H,H,H,H,S,S,S,x,N,E,E,L,L,L,E,E,E,E,E,k,C,k,C,C,b,b,b,b,b,b,b,b,b,b,C,E,E,E,E,E,E,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,E,E,E,E,E,E,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,g,E,E,E,E,H,H,H,H,H,H,S,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,C,E,L,L,L,L,E,E,E,E,g,E,E,H,E,E,L,L,b,b,E,g,E,E,E,b,g,E,E,E,E,E],j=[N,N,N,N,N,N,N,N,N,N,N,H,H,H,g,y,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,N,S,O,M,_,D,P,C,L,L,L,L,L,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,C,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,E,N];t.L=g,t.R=y,t.EN=b,t.ON_R=3,t.AN=4,t.R_H=5,t.B=6,t.RLE=7,t.DOT="\u00b7",t.doBidiReorder=function(e,n,r){if(e.length<2)return{};var i=e.split(""),o=new Array(i.length),u=new Array(i.length),a=[];s=r?m:v,F(i,a,i.length,n);for(var f=0;fT&&n[f]0&&i[f-1]==="\u0644"&&/\u0622|\u0623|\u0625|\u0627/.test(i[f])&&(a[f-1]=a[f]=t.R_H,f++);i[i.length-1]===t.DOT&&(a[i.length-1]=t.B),i[0]==="\u202b"&&(a[0]=t.RLE);for(var f=0;f=0&&(e=this.session.$docRowCache[n])}return e},this.getSplitIndex=function(){var e=0,t=this.session.$screenRowCache;if(t.length){var n,r=this.session.$getRowCacheIndex(t,this.currentRow);while(this.currentRow-e>0){n=this.session.$getRowCacheIndex(t,this.currentRow-e-1);if(n!==r)break;r=n,e++}}else e=this.currentRow;return e},this.updateRowLine=function(e,t){e===undefined&&(e=this.getDocumentRow());var n=e===this.session.getLength()-1,s=n?this.EOF:this.EOL;this.wrapIndent=0,this.line=this.session.getLine(e),this.isRtlDir=this.$isRtl||this.line.charAt(0)===this.RLE;if(this.session.$useWrapMode){var o=this.session.$wrapData[e];o&&(t===undefined&&(t=this.getSplitIndex()),t>0&&o.length?(this.wrapIndent=o.indent,this.wrapOffset=this.wrapIndent*this.charWidths[r.L],this.line=tt?this.session.getOverwrite()?e:e-1:t,i=r.getVisualFromLogicalIdx(n,this.bidiMap),s=this.bidiMap.bidiLevels,o=0;!this.session.getOverwrite()&&e<=t&&s[i]%2!==0&&i++;for(var u=0;ut&&s[i]%2===0&&(o+=this.charWidths[s[i]]),this.wrapIndent&&(o+=this.isRtlDir?-1*this.wrapOffset:this.wrapOffset),this.isRtlDir&&(o+=this.rtlLineOffset),o},this.getSelections=function(e,t){var n=this.bidiMap,r=n.bidiLevels,i,s=[],o=0,u=Math.min(e,t)-this.wrapIndent,a=Math.max(e,t)-this.wrapIndent,f=!1,l=!1,c=0;this.wrapIndent&&(o+=this.isRtlDir?-1*this.wrapOffset:this.wrapOffset);for(var h,p=0;p=u&&hn+s/2){n+=s;if(r===i.length-1){s=0;break}s=this.charWidths[i[++r]]}return r>0&&i[r-1]%2!==0&&i[r]%2===0?(e0&&i[r-1]%2===0&&i[r]%2!==0?t=1+(e>n?this.bidiMap.logicalFromVisual[r]:this.bidiMap.logicalFromVisual[r-1]):this.isRtlDir&&r===i.length-1&&s===0&&i[r-1]%2===0||!this.isRtlDir&&r===0&&i[r]%2!==0?t=1+this.bidiMap.logicalFromVisual[r]:(r>0&&i[r-1]%2!==0&&s!==0&&r--,t=this.bidiMap.logicalFromVisual[r]),t===0&&this.isRtlDir&&t++,t+this.wrapIndent}}).call(o.prototype),t.BidiHandler=o}),ace.define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.cursor=this.lead=this.doc.createAnchor(0,0),this.anchor=this.doc.createAnchor(0,0),this.$silent=!1;var t=this;this.cursor.on("change",function(e){t.$cursorChanged=!0,t.$silent||t._emit("changeCursor"),!t.$isEmpty&&!t.$silent&&t._emit("changeSelection"),!t.$keepDesiredColumnOnChange&&e.old.column!=e.value.column&&(t.$desiredColumn=null)}),this.anchor.on("change",function(){t.$anchorChanged=!0,!t.$isEmpty&&!t.$silent&&t._emit("changeSelection")})};(function(){r.implement(this,s),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return!this.$isEmpty&&this.anchor.row!=this.cursor.row},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.$isEmpty=!1,this.anchor.setPosition(e,t)},this.getAnchor=this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.$isEmpty?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){this.$setSelection(0,0,Number.MAX_VALUE,Number.MAX_VALUE)},this.setRange=this.setSelectionRange=function(e,t){var n=t?e.end:e.start,r=t?e.start:e.end;this.$setSelection(n.row,n.column,r.row,r.column)},this.$setSelection=function(e,t,n,r){var i=this.$isEmpty,s=this.inMultiSelectMode;this.$silent=!0,this.$cursorChanged=this.$anchorChanged=!1,this.anchor.setPosition(e,t),this.cursor.setPosition(n,r),this.$isEmpty=!o.comparePoints(this.anchor,this.cursor),this.$silent=!1,this.$cursorChanged&&this._emit("changeCursor"),(this.$cursorChanged||this.$anchorChanged||i!=this.$isEmpty||s)&&this._emit("changeSelection")},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t===!0?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.wouldMoveIntoSoftTab=function(e,t,n){var r=e.column,i=e.column+t;return n<0&&(r=e.column-t,i=e.column),this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(r,i).split(" ").length-1==t},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column===0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.wouldMoveIntoSoftTab(e,n,-1)&&!this.session.getNavigateWithinSoftTabs()?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t);this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var i=this.session.getFoldAt(e,t,1);if(i){this.moveCursorTo(i.end.row,i.end.column);return}this.session.nonTokenRe.exec(r)&&(t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t));if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e0&&this.moveCursorWordLeft();return}this.session.tokenRe.exec(s)&&(t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0),this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t=0,n,r=/\s/,i=this.session.tokenRe;i.lastIndex=0;if(this.session.tokenRe.exec(e))t=this.session.tokenRe.lastIndex;else{while((n=e[t])&&r.test(n))t++;if(t<1){i.lastIndex=0;while((n=e[t])&&!i.test(n)){i.lastIndex=0,t++;if(r.test(n)){if(t>2){t--;break}while((n=e[t])&&r.test(n))t++;if(t>2)break}}}}return i.lastIndex=0,t},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column),r;t===0&&(e!==0&&(this.session.$bidiHandler.isBidiRow(n.row,this.lead.row)?(r=this.session.$bidiHandler.getPosLeft(n.column),n.column=Math.round(r/this.session.$bidiHandler.charWidths[0])):r=n.column*this.session.$bidiHandler.charWidths[0]),this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);var i=this.session.screenToDocumentPosition(n.row+e,n.column,r);e!==0&&t===0&&i.row===this.lead.row&&i.column===this.lead.column&&this.session.lineWidgets&&this.session.lineWidgets[i.row]&&(i.row>0||e>0)&&i.row++,this.moveCursorTo(i.row,i.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0;var i=this.session.getLine(e);/[\uDC00-\uDFFF]/.test(i.charAt(t))&&i.charAt(t-1)&&(this.lead.row==e&&this.lead.column==t+1?t-=1:t+=1),this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return o.fromPoints(t,n)}catch(r){return o.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{var e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(e.start==undefined){if(this.rangeList&&e.length>1){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=o.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(u.prototype),t.Selection=u}),ace.define("ace/tokenizer",["require","exports","module","ace/config"],function(e,t,n){"use strict";var r=e("./config"),i=2e3,s=function(e){this.states=e,this.regExps={},this.matchMappings={};for(var t in this.states){var n=this.states[t],r=[],i=0,s=this.matchMappings[t]={defaultToken:"text"},o="g",u=[];for(var a=0;a1?f.onMatch=this.$applyToken:f.onMatch=f.token),c>1&&(/\\\d/.test(f.regex)?l=f.regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+i+1)}):(c=1,l=this.removeCapturingGroups(f.regex)),!f.splitRegex&&typeof f.token!="string"&&u.push(f)),s[i]=a,i+=c,r.push(l),f.onMatch||(f.onMatch=null)}r.length||(s[0]=0,r.push("$")),u.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,o)},this),this.regExps[t]=new RegExp("("+r.join(")|(")+")|($)",o)}};(function(){this.$setMaxTokenCount=function(e){i=e|0},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(typeof n=="string")return[{type:n,value:e}];var r=[];for(var i=0,s=n.length;il){var g=e.substring(l,m-v.length);h.type==p?h.value+=g:(h.type&&f.push(h),h={type:p,value:g})}for(var y=0;yi){c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});while(l1&&n[0]!==r&&n.unshift("#tmp",r),{tokens:f,state:n.length?n:r}},this.reportError=r.reportError}).call(s.prototype),t.Tokenizer=s}),ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{defaultToken:"text"}]}};(function(){this.addRules=function(e,t){if(!t){for(var n in e)this.$rules[n]=e[n];return}for(var n in e){var r=e[n];for(var i=0;i=this.$rowTokens.length){this.$row+=1,e||(e=this.$session.getLength());if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}},this.getCurrentTokenRange=function(){var e=this.$rowTokens[this.$tokenIndex],t=this.getCurrentTokenColumn();return new r(this.$row,t,this.$row,t+e.value.length)}}).call(i.prototype),t.TokenIterator=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f,l={},c={'"':'"',"'":"'"},h=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},p=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},d=function(e){this.add("braces","insertion",function(t,n,r,i,s){var u=r.getCursorPosition(),a=i.doc.getLine(u.row);if(s=="{"){h(r);var l=r.getSelectionRange(),c=i.doc.getTextRange(l);if(c!==""&&c!=="{"&&r.getWrapBehavioursEnabled())return p(l,c,"{","}");if(d.isSaneInsertion(r,i))return/[\]\}\)]/.test(a[u.column])||r.inMultiSelectMode||e&&e.braces?(d.recordAutoInsert(r,i,"}"),{text:"{}",selection:[1,1]}):(d.recordMaybeInsert(r,i,"{"),{text:"{",selection:[1,1]})}else if(s=="}"){h(r);var v=a.substring(u.column,u.column+1);if(v=="}"){var m=i.$findOpeningBracket("}",{column:u.column+1,row:u.row});if(m!==null&&d.isAutoInsertedClosing(u,a,s))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(s=="\n"||s=="\r\n"){h(r);var g="";d.isMaybeInsertedClosing(u,a)&&(g=o.stringRepeat("}",f.maybeInsertedBrackets),d.clearMaybeInsertedClosing());var v=a.substring(u.column,u.column+1);if(v==="}"){var y=i.findMatchingBracket({row:u.row,column:u.column+1},"}");if(!y)return null;var b=this.$getIndent(i.getLine(y.row))}else{if(!g){d.clearMaybeInsertedClosing();return}var b=this.$getIndent(a)}var w=b+i.getTabString();return{text:"\n"+w+"\n"+b+g,selection:[1,w.length,1,w.length]}}d.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){h(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return p(s,o,"(",")");if(d.isSaneInsertion(n,r))return d.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){h(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&d.isAutoInsertedClosing(u,a,i))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){h(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return p(s,o,"[","]");if(d.isSaneInsertion(n,r))return d.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){h(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&d.isAutoInsertedClosing(u,a,i))return d.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){h(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){var s=r.$mode.$quotes||c;if(i.length==1&&s[i]){if(this.lineCommentStart&&this.lineCommentStart.indexOf(i)!=-1)return;h(n);var o=i,u=n.getSelectionRange(),a=r.doc.getTextRange(u);if(a!==""&&(a.length!=1||!s[a])&&n.getWrapBehavioursEnabled())return p(u,a,o,o);if(!a){var f=n.getCursorPosition(),l=r.doc.getLine(f.row),d=l.substring(f.column-1,f.column),v=l.substring(f.column,f.column+1),m=r.getTokenAt(f.row,f.column),g=r.getTokenAt(f.row,f.column+1);if(d=="\\"&&m&&/escape/.test(m.type))return null;var y=m&&/string|escape/.test(m.type),b=!g||/string|escape/.test(g.type),w;if(v==o)w=y!==b,w&&/string\.end/.test(g.type)&&(w=!1);else{if(y&&!b)return null;if(y&&b)return null;var E=r.$mode.tokenRe;E.lastIndex=0;var S=E.test(d);E.lastIndex=0;var x=E.test(d);if(S||x)return null;if(v&&!/[\s;,.})\]\\]/.test(v))return null;w=!0}return{text:w?o+o:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.$mode.$quotes||c,o=r.doc.getTextRange(i);if(!i.isMultiLine()&&s.hasOwnProperty(o)){h(n);var u=r.doc.getLine(i.start.row),a=u.substring(i.start.column+1,i.start.column+2);if(a==o)return i.end.column++,i}})};d.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},d.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},d.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},d.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},d.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},d.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},d.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},d.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(d,i),t.CstyleBehaviour=d}),ace.define("ace/unicode",["require","exports","module"],function(e,t,n){"use strict";var r=[48,9,8,25,5,0,2,25,48,0,11,0,5,0,6,22,2,30,2,457,5,11,15,4,8,0,2,0,18,116,2,1,3,3,9,0,2,2,2,0,2,19,2,82,2,138,2,4,3,155,12,37,3,0,8,38,10,44,2,0,2,1,2,1,2,0,9,26,6,2,30,10,7,61,2,9,5,101,2,7,3,9,2,18,3,0,17,58,3,100,15,53,5,0,6,45,211,57,3,18,2,5,3,11,3,9,2,1,7,6,2,2,2,7,3,1,3,21,2,6,2,0,4,3,3,8,3,1,3,3,9,0,5,1,2,4,3,11,16,2,2,5,5,1,3,21,2,6,2,1,2,1,2,1,3,0,2,4,5,1,3,2,4,0,8,3,2,0,8,15,12,2,2,8,2,2,2,21,2,6,2,1,2,4,3,9,2,2,2,2,3,0,16,3,3,9,18,2,2,7,3,1,3,21,2,6,2,1,2,4,3,8,3,1,3,2,9,1,5,1,2,4,3,9,2,0,17,1,2,5,4,2,2,3,4,1,2,0,2,1,4,1,4,2,4,11,5,4,4,2,2,3,3,0,7,0,15,9,18,2,2,7,2,2,2,22,2,9,2,4,4,7,2,2,2,3,8,1,2,1,7,3,3,9,19,1,2,7,2,2,2,22,2,9,2,4,3,8,2,2,2,3,8,1,8,0,2,3,3,9,19,1,2,7,2,2,2,22,2,15,4,7,2,2,2,3,10,0,9,3,3,9,11,5,3,1,2,17,4,23,2,8,2,0,3,6,4,0,5,5,2,0,2,7,19,1,14,57,6,14,2,9,40,1,2,0,3,1,2,0,3,0,7,3,2,6,2,2,2,0,2,0,3,1,2,12,2,2,3,4,2,0,2,5,3,9,3,1,35,0,24,1,7,9,12,0,2,0,2,0,5,9,2,35,5,19,2,5,5,7,2,35,10,0,58,73,7,77,3,37,11,42,2,0,4,328,2,3,3,6,2,0,2,3,3,40,2,3,3,32,2,3,3,6,2,0,2,3,3,14,2,56,2,3,3,66,5,0,33,15,17,84,13,619,3,16,2,25,6,74,22,12,2,6,12,20,12,19,13,12,2,2,2,1,13,51,3,29,4,0,5,1,3,9,34,2,3,9,7,87,9,42,6,69,11,28,4,11,5,11,11,39,3,4,12,43,5,25,7,10,38,27,5,62,2,28,3,10,7,9,14,0,89,75,5,9,18,8,13,42,4,11,71,55,9,9,4,48,83,2,2,30,14,230,23,280,3,5,3,37,3,5,3,7,2,0,2,0,2,0,2,30,3,52,2,6,2,0,4,2,2,6,4,3,3,5,5,12,6,2,2,6,67,1,20,0,29,0,14,0,17,4,60,12,5,0,4,11,18,0,5,0,3,9,2,0,4,4,7,0,2,0,2,0,2,3,2,10,3,3,6,4,5,0,53,1,2684,46,2,46,2,132,7,6,15,37,11,53,10,0,17,22,10,6,2,6,2,6,2,6,2,6,2,6,2,6,2,6,2,31,48,0,470,1,36,5,2,4,6,1,5,85,3,1,3,2,2,89,2,3,6,40,4,93,18,23,57,15,513,6581,75,20939,53,1164,68,45,3,268,4,27,21,31,3,13,13,1,2,24,9,69,11,1,38,8,3,102,3,1,111,44,25,51,13,68,12,9,7,23,4,0,5,45,3,35,13,28,4,64,15,10,39,54,10,13,3,9,7,22,4,1,5,66,25,2,227,42,2,1,3,9,7,11171,13,22,5,48,8453,301,3,61,3,105,39,6,13,4,6,11,2,12,2,4,2,0,2,1,2,1,2,107,34,362,19,63,3,53,41,11,5,15,17,6,13,1,25,2,33,4,2,134,20,9,8,25,5,0,2,25,12,88,4,5,3,5,3,5,3,2],i=0,s=[];for(var o=0;o2?r%f!=f-1:r%f==0}}var E=Infinity;w(function(e,t){var n=e.search(/\S/);n!==-1?(ne.length&&(E=e.length)}),u==Infinity&&(u=E,s=!1,o=!1),l&&u%f!=0&&(u=Math.floor(u/f)*f),w(o?m:v)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(!i)return;!i.start&&i[0]&&(i=i[0]);var s=new f(t,r.row,r.column),o=s.getCurrentToken(),u=t.selection,a=t.selection.toOrientedRange(),c,h;if(o&&/comment/.test(o.type)){var p,d;while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.start);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;p=new l(m,g,m,g+i.start.length);break}o=s.stepBackward()}var s=new f(t,r.row,r.column),o=s.getCurrentToken();while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.end);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;d=new l(m,g,m,g+i.end.length);break}o=s.stepForward()}d&&t.remove(d),p&&(t.remove(p),c=p.start.row,h=-i.start.length)}else h=i.start.length,c=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);a.start.row==c&&(a.start.column+=h),a.end.row==c&&(a.end.column+=h),t.selection.fromOrientedRange(a)},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){this.$embeds=[],this.$modes={};for(var t in e)if(e[t]){var n=e[t],i=n.prototype.$id,s=r.$modes[i];s||(r.$modes[i]=s=new n),r.$modes[t]||(r.$modes[t]=s),this.$embeds.push(t),this.$modes[t]=s}var o=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"];for(var t=0;t=0&&t.row=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.columnthis.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e0,r=t=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4?this.$splitAndapplyLargeDelta(e,2e4):(i(this.$lines,e,t),this._signal("change",e))},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length-t+1,i=e.start.row,s=e.start.column;for(var o=0,u=0;o20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,r==-1&&(r=t),s<=r&&n.fireUpdateEvent(s,r)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.lines[t]=null;else if(e.action=="remove")this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+""!=r.state+""?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(s.prototype),t.BackgroundTokenizer=s}),ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i)}}}).call(o.prototype),t.SearchHighlight=o}),ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.rowthis.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f0)continue;var a=i(e,o.start);return u===0?t&&a!==0?-s-2:s:a>0||a===0&&!t?s:-s-1}return-s-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});var n=t[0],r;for(var s=1;s=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row=r)break}if(e.action=="insert"){var f=i-r,l=-t.column+n.column;for(;or)break;a.start.row==r&&a.start.column>=t.column&&(a.start.column!=t.column||!this.$insertRight)&&(a.start.column+=l,a.start.row+=f);if(a.end.row==r&&a.end.column>=t.column){if(a.end.column==t.column&&this.$insertRight)continue;a.end.column==t.column&&l>0&&oa.start.column&&a.end.column==s[o+1].start.column&&(a.end.column-=l),a.end.column+=l,a.end.row+=f}}}else{var f=r-i,l=t.column-n.column;for(;oi)break;if(a.end.rowt.column)a.end.column=t.column,a.end.row=t.row}else a.end.column+=l,a.end.row+=f;else a.end.row>i&&(a.end.row+=f);if(a.start.rowt.column)a.start.column=t.column,a.start.row=t.row}else a.start.column+=l,a.start.row+=f;else a.start.row>i&&(a.start.row+=f)}}if(f!=0&&o=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i=t){u=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:(o=new s(t,e),o.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column;if(u0&&(this.removeFolds(p),p.forEach(function(e){o.addSubFold(e)}));for(var d=0;d0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;e==null?(n=new r(0,0,this.getLength(),0),t=!0):typeof e=="number"?n=new r(e,0,e,this.getLine(e).length):"row"in e?n=r.fromPoints(e,e):n=e,i=this.getFoldsInRangeList(n);if(t)this.removeFolds(i);else{var s=i;while(s.length)this.expandFolds(s),s=this.getFoldsInRangeList(n)}if(i.length)return i},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row),i==null&&(i=0),t==null&&(t=e.end.row),n==null&&(n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(tl)break}while(s&&a.test(s.type));s=i.stepBackward()}else s=i.getCurrentToken();return f.end.row=i.getCurrentTokenRow(),f.end.column=i.getCurrentTokenColumn()+s.value.length-2,f}},this.foldAll=function(e,t,n){n==undefined&&(n=1e5);var r=this.foldWidgets;if(!r)return;t=t||this.getLength(),e=e||0;for(var i=e;i=e){i=s.end.row;try{var o=this.addFold("...",s);o&&(o.collapseChildren=n)}catch(u){}}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle="markbegin",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error("invalid fold style: "+e+"["+Object.keys(this.$foldStyles).join(", ")+"]");if(this.$foldStyle==e)return;this.$foldStyle=e,e=="manual"&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)},this.$setFolding=function(e){if(this.$foldMode==e)return;this.$foldMode=e,this.off("change",this.$updateFoldWidgets),this.off("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets),this._signal("changeAnnotation");if(!e||this.$foldStyle=="manual"){this.foldWidgets=null;return}this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.$tokenizerUpdateFoldWidgets=this.tokenizerUpdateFoldWidgets.bind(this),this.on("change",this.$updateFoldWidgets),this.on("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets)},this.getParentFoldRangeData=function(e,t){var n=this.foldWidgets;if(!n||t&&n[e])return{};var r=e-1,i;while(r>=0){var s=n[r];s==null&&(s=n[r]=this.getFoldWidget(r));if(s=="start"){var o=this.getFoldWidgetRange(r);i||(i=o);if(o&&o.end.row>=e)break}r--}return{range:r!==-1&&o,firstRange:i}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")}},this.$toggleFoldWidget=function(e,t){if(!this.getFoldWidget)return;var n=this.getFoldWidget(e),r=this.getLine(e),i=n==="end"?-1:1,s=this.getFoldAt(e,i===-1?0:r.length,i);if(s)return t.children||t.all?this.removeFold(s):this.expandFold(s),s;var o=this.getFoldWidgetRange(e,!0);if(o&&!o.isMultiLine()){s=this.getFoldAt(o.start.row,o.start.column,1);if(s&&o.isEqual(s.range))return this.removeFold(s),s}if(t.siblings){var u=this.getParentFoldRangeData(e);if(u.range)var a=u.range.start.row+1,f=u.range.end.row;this.foldAll(a,f,t.all?1e4:0)}else t.children?(f=o?o.end.row:this.getLength(),this.foldAll(e+1,f,t.all?1e4:0)):o&&(t.all&&(o.collapseChildren=1e4),this.addFold("...",o));return o},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(n)return;var r=this.getParentFoldRangeData(t,!0);n=r.range||r.firstRange;if(n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold("...",n)}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.foldWidgets[t]=null;else if(e.action=="remove")this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){"use strict";function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{","<":">",">":"<"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}r.implement(this,u),this.setDocument=function(e){this.doc&&this.doc.removeListener("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;e.addSession(this),this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.mergeUndoDeltas=!1},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}else this.$syncInformUndoManager=function(){}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){},add:function(){},addSelection:function(){},startNewGroup:function(){},addSession:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(" ",this.getTabSize()):" "},this.setUseSoftTabs=function(e){this.setOption("useSoftTabs",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption("tabSize",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.setNavigateWithinSoftTabs=function(e){this.setOption("navigateWithinSoftTabs",e)},this.getNavigateWithinSoftTabs=function(){return this.$navigateWithinSoftTabs},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption("overwrite",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._signal("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._signal("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(oe&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;ao){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;for(var n=e.length-1;n!=-1;n--){var r=e[n];r.action=="insert"||r.action=="remove"?this.doc.revertDelta(r):r.folds&&this.addFolds(r.folds)}!t&&this.$undoSelect&&(e.selectionBefore?this.selection.fromJSON(e.selectionBefore):this.selection.setRange(this.$getUndoSelection(e,!0))),this.$fromUndo=!1},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;for(var n=0;ne.end.column&&(s.start.column+=u),s.end.row==e.end.row&&s.end.column>e.end.column&&(s.end.column+=u)),o&&s.start.row>=e.end.row&&(s.start.row+=o,s.end.row+=o)}s.end=this.insert(s.start,r);if(i.length){var a=e.start,f=s.start,o=f.row-a.row,u=f.column-a.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==a.row&&(e.start.column+=u),e.end.row==a.row&&(e.end.column+=u),e.start.row+=o,e.end.row+=o,e}))}return s},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new l(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o0){var r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;var i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);var i=t-e+1}var s=new l(e,0,t,Number.MAX_VALUE),o=this.getFoldsInRange(s).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),u=n==0?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,u),o.length&&this.addFolds(o),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$bidiHandler.markAsDirty(),this.$useWrapMode&&this._signal("changeWrapMode")},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1?(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=null;this.$updating=!0;if(u!=0)if(n==="remove"){this[t?"$wrapData":"$rowLengthCache"].splice(s,u);var f=this.$foldData;a=this.getFoldsInRange(e),this.removeFolds(a);var l=this.getFoldLine(i.row),c=0;if(l){l.addRemoveChars(i.row,i.column,r.column-i.column),l.shiftRow(-u);var h=this.getFoldLine(s);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c=i.row&&l.shiftRow(-u)}o=s}else{var p=Array(u);p.unshift(s,0);var d=t?this.$wrapData:this.$rowLengthCache;d.splice.apply(d,p);var f=this.$foldData,l=this.getFoldLine(s),c=0;if(l){var v=l.range.compareInside(r.row,r.column);v==0?(l=l.split(r.row,r.column),l&&(l.shiftRow(u),l.addRemoveChars(o,0,i.column-r.column))):v==-1&&(l.addRemoveChars(s,0,i.column-r.column),l.shiftRow(u)),c=f.indexOf(l)+1}for(c;c=s&&l.shiftRow(u)}}else{u=Math.abs(e.start.column-e.end.column),n==="remove"&&(a=this.getFoldsInRange(e),this.removeFolds(a),u=-u);var l=this.getFoldLine(s);l&&l.addRemoveChars(s,r.column,u)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(s,o):this.$updateRowLengthCache(s,o),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r=this.doc.getAllLines(),i=this.getTabSize(),o=this.$wrapData,u=this.$wrapLimit,a,f,l=e;t=Math.min(t,r.length-1);while(l<=t)f=this.getFoldLine(l,f),f?(a=[],f.walk(function(e,t,i,o){var u;if(e!=null){u=this.$getDisplayTokens(e,a.length),u[0]=n;for(var f=1;fr-b){var w=f+r-b;if(e[w-1]>=c&&e[w]>=c){y(w);continue}if(e[w]==n||e[w]==s){for(w;w!=f-1;w--)if(e[w]==n)break;if(w>f){y(w);continue}w=f+r;for(w;w>2)),f-1);while(w>E&&e[w]E&&e[w]E&&e[w]==a)w--}else while(w>E&&e[w]E){y(++w);continue}w=f+r,e[w]==t&&w--,y(w-b)}return o},this.$getDisplayTokens=function(n,r){var i=[],s;r=r||0;for(var o=0;o39&&u<48||u>57&&u<64?i.push(a):u>=4352&&m(u)?i.push(e,t):i.push(e)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i=4352&&m(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){if(this.lineWidgets)var t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;else t=0;return!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.getRowLineCount=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]=0)var u=f[l],i=this.$docRowCache[l],h=e>f[c-1];else var h=!c;var p=this.getLength()-1,d=this.getNextFoldLine(i),v=d?d.start.row:Infinity;while(u<=e){a=this.getRowLength(i);if(u+a>e||i>=p)break;u+=a,i++,i>v&&(i=d.end.row+1,d=this.getNextFoldLine(i,d),v=d?d.start.row:Infinity),h&&(this.$docRowCache.push(i),this.$screenRowCache.push(u))}if(d&&d.start.row<=i)r=this.getFoldDisplayLine(d),i=d.start.row;else{if(u+a<=e||i>p)return{row:p,column:this.getLine(p).length};r=this.getLine(i),d=null}var m=0,g=Math.floor(e-u);if(this.$useWrapMode){var y=this.$wrapData[i];y&&(o=y[g],g>0&&y.length&&(m=y.indent,s=y[g-1]||y[y.length-1],r=r.substring(s)))}return n!==undefined&&this.$bidiHandler.isBidiRow(u+g,i,g)&&(t=this.$bidiHandler.offsetToCol(n)),s+=this.$getStringScreenWidth(r,t-m)[1],this.$useWrapMode&&s>=o&&(s=o-1),d?d.idxToPosition(s):{row:i,column:s}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);var v=0;if(this.$useWrapMode){var m=this.$wrapData[i];if(m){var g=0;while(d.length>=m[g])r++,g++;d=d.substring(m[g-1]||0,d.length),v=g>0?m.indent:0}}return{row:r,column:v+this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;ro&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){if(!this.$enableVarChar)return;this.$getStringScreenWidth=function(t,n,r){if(n===0)return[0,0];n||(n=Infinity),r=r||0;var i,s;for(s=0;sn)break}return[r,s]}},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker()},this.isFullWidth=m}.call(d.prototype),e("./edit_session/folding").Folding.call(d.prototype),e("./edit_session/bracket_match").BracketMatch.call(d.prototype),o.defineOptions(d.prototype,"session",{wrap:{set:function(e){!e||e=="off"?e=!1:e=="free"?e=!0:e=="printMargin"?e=-1:typeof e=="string"&&(e=parseInt(e,10)||!1);if(this.$wrap==e)return;this.$wrap=e;if(!e)this.setUseWrapMode(!1);else{var t=typeof e=="number"?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}},get:function(){return this.getUseWrapMode()?this.$wrap==-1?"printMargin":this.getWrapLimitRange().min?this.$wrap:"free":"off"},handlesSet:!0},wrapMethod:{set:function(e){e=e=="auto"?this.$mode.type!="text":e!="text",e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$useWrapMode=!1,this.setUseWrapMode(!0)))},initialValue:"auto"},indentedSoftWrap:{set:function(){this.$useWrapMode&&(this.$useWrapMode=!1,this.setUseWrapMode(!0))},initialValue:!0},firstLineNumber:{set:function(){this._signal("changeBreakpoint")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){e=parseInt(e);if(isNaN(e)||this.$tabSize===e)return;this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal("changeTabSize")},initialValue:4,handlesSet:!0},navigateWithinSoftTabs:{initialValue:!1},foldStyle:{set:function(e){this.setFoldStyle(e)},handlesSet:!0},overwrite:{set:function(e){this._signal("changeOverwrite")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId},handlesSet:!0}}),t.EditSession=d}),ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";function u(e,t){function n(e){return/\w/.test(e)||t.regExp?"\\b":""}return n(e[0])+e+n(e[e.length-1])}var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i,o){return r=new s(e,n,i,o),n==o&&t.start&&t.start.start&&t.skipCurrent!=0&&r.isEqual(t.start)?(r=null,!1):!0}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a,l;e:for(var c=u.offset||0;c<=f;c++){for(var h=0;hv)continue;o.push(l=new s(c,v,c+a-1,m)),a>2&&(c=c+a-2)}}else for(var g=0;gE&&o[h].end.row==n.end.row)h--;o=o.slice(g,h+1);for(g=0,h=o.length;g=u;n--)if(c(n,Number.MAX_VALUE,e))return;if(t.wrap==0)return;for(n=a,u=o.row;n>=u;n--)if(c(n,Number.MAX_VALUE,e))return};else var f=function(e){var n=o.row;if(c(n,o.column,e))return;for(n+=1;n<=a;n++)if(c(n,0,e))return;if(t.wrap==0)return;for(n=u,a=o.row;n<=a;n++)if(c(n,0,e))return};if(t.$isMultiLine)var l=n.length,c=function(t,i,s){var o=r?t-l+1:t;if(o<0)return;var u=e.getLine(o),a=u.search(n[0]);if(!r&&ai)return;if(s(o,a,o+l-1,c))return!0};else if(r)var c=function(t,r,i){var s=e.getLine(t),o=[],u,a=0;n.lastIndex=0;while(u=n.exec(s)){var f=u[0].length;a=u.index;if(!f){if(a>=s.length)break;n.lastIndex=a+=1}if(u.index+f>r)break;o.push(u.index,f)}for(var l=o.length-1;l>=0;l-=2){var c=o[l-1],f=o[l];if(i(t,c,t,c+f))return!0}};else var c=function(t,r,i){var s=e.getLine(t),o,u;n.lastIndex=r;while(u=n.exec(s)){var a=u[0].length;o=u.index;if(i(t,o,t,o+a))return!0;if(!a){n.lastIndex=o+=1;if(o>=s.length)return!1}}};return{forEach:f}}}).call(o.prototype),t.Search=o}),ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function u(e,t){o.call(this,e,t),this.$singleCommand=!1}var r=e("../lib/keys"),i=e("../lib/useragent"),s=r.KEY_MODS;u.prototype=o.prototype,function(){function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||(e.isDefault?-100:0)}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(typeof e=="string"?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var s=r[i];if(s==e)delete r[i];else if(Array.isArray(s)){var o=s.indexOf(e);o!=-1&&(s.splice(o,1),s.length==1&&(r[i]=s[0]))}}},this.bindKey=function(e,t,n){typeof e=="object"&&e&&(n==undefined&&(n=e.position),e=e[this.platform]);if(!e)return;if(typeof t=="function")return this.addCommand({exec:t,bindKey:e,name:t.name||e});e.split("|").forEach(function(e){var r="";if(e.indexOf(" ")!=-1){var i=e.split(/\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=s[t.hashId]+t.key;r+=(r?" ":"")+n,this._addCommandToBinding(r,"chainKeys")},this),r+=" "}var o=this.parseKeys(e),u=s[o.hashId]+o.key;this._addCommandToBinding(r+u,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i=this.commandKeyBinding,s;if(!n)delete i[t];else if(!i[t]||this.$singleCommand)i[t]=n;else{Array.isArray(i[t])?(s=i[t].indexOf(n))!=-1&&i[t].splice(s,1):i[t]=[i[t]],typeof r!="number"&&(r=e(n));var o=i[t];for(s=0;sr)break}o.splice(s,0,n)}},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(!n)return;if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n});if(typeof n!="object")return;n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)return typeof console!="undefined"&&console.error("invalid modifier "+t[o]+" in "+e),!1;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=s[t]+n;return this.commandKeyBinding[r]},this.handleKeyboard=function(e,t,n,r){if(r<0)return;var i=s[t]+n,o=this.commandKeyBinding[i];e.$keyChain&&(e.$keyChain+=" "+i,o=this.commandKeyBinding[e.$keyChain]||o);if(o)if(o=="chainKeys"||o[o.length-1]=="chainKeys")return e.$keyChain=e.$keyChain||i,{command:"null"};if(e.$keyChain)if(!!t&&t!=4||n.length!=1){if(t==-1||r>0)e.$keyChain=""}else e.$keyChain=e.$keyChain.slice(0,-i.length-1);return{command:o}},this.getStatusText=function(e,t){return t.$keyChain||""}}.call(o.prototype),t.HashHandler=o,t.MultiHashHandler=u}),ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../keyboard/hash_handler").MultiHashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;if(this.$checkCommandState!=0&&e.isAvailable&&!e.isAvailable(t))return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit("exec",i),this._signal("afterExec",i),i.returnValue===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.removeEventListener("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"],function(e,t,n){"use strict";function o(e,t){return{win:e,mac:t}}var r=e("../lib/lang"),i=e("../config"),s=e("../range").Range;t.commands=[{name:"showSettingsMenu",bindKey:o("Ctrl-,","Command-,"),exec:function(e){i.loadModule("ace/ext/settings_menu",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:"goToNextError",bindKey:o("Alt-E","F4"),exec:function(e){i.loadModule("./ext/error_marker",function(t){t.showErrorMarker(e,1)})},scrollIntoView:"animate",readOnly:!0},{name:"goToPreviousError",bindKey:o("Alt-Shift-E","Shift-F4"),exec:function(e){i.loadModule("./ext/error_marker",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:"animate",readOnly:!0},{name:"selectall",description:"Select all",bindKey:o("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",description:"Center selection",bindKey:o(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",description:"Go to line...",bindKey:o("Ctrl-L","Command-L"),exec:function(e,t){typeof t=="number"&&!isNaN(t)&&e.gotoLine(t),e.prompt({$type:"gotoLine"})},readOnly:!0},{name:"fold",bindKey:o("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"unfold",bindKey:o("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleFoldWidget",bindKey:o("F2","F2"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleParentFoldWidget",bindKey:o("Alt-F2","Alt-F2"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"foldall",description:"Fold all",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAll()},scrollIntoView:"center",readOnly:!0},{name:"foldOther",description:"Fold other",bindKey:o("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:"center",readOnly:!0},{name:"unfoldall",description:"Unfold all",bindKey:o("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},scrollIntoView:"center",readOnly:!0},{name:"findnext",description:"Find next",bindKey:o("Ctrl-K","Command-G"),exec:function(e){e.findNext()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"findprevious",description:"Find previous",bindKey:o("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"selectOrFindNext",description:"Select or find next",bindKey:o("Alt-K","Ctrl-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:"selectOrFindPrevious",description:"Select or find previous",bindKey:o("Alt-Shift-K","Ctrl-Shift-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:"find",description:"Find",bindKey:o("Ctrl-F","Command-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e)})},readOnly:!0},{name:"overwrite",description:"Overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",description:"Select to start",bindKey:o("Ctrl-Shift-Home","Command-Shift-Home|Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotostart",description:"Go to start",bindKey:o("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectup",description:"Select up",bindKey:o("Shift-Up","Shift-Up|Ctrl-Shift-P"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golineup",description:"Go line up",bindKey:o("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttoend",description:"Select to end",bindKey:o("Ctrl-Shift-End","Command-Shift-End|Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotoend",description:"Go to end",bindKey:o("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectdown",description:"Select down",bindKey:o("Shift-Down","Shift-Down|Ctrl-Shift-N"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golinedown",description:"Go line down",bindKey:o("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordleft",description:"Select word left",bindKey:o("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordleft",description:"Go to word left",bindKey:o("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolinestart",description:"Select to line start",bindKey:o("Alt-Shift-Left","Command-Shift-Left|Ctrl-Shift-A"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolinestart",description:"Go to line start",bindKey:o("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectleft",description:"Select left",bindKey:o("Shift-Left","Shift-Left|Ctrl-Shift-B"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoleft",description:"Go to left",bindKey:o("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordright",description:"Select word right",bindKey:o("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordright",description:"Go to word right",bindKey:o("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolineend",description:"Select to line end",bindKey:o("Alt-Shift-Right","Command-Shift-Right|Shift-End|Ctrl-Shift-E"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolineend",description:"Go to line end",bindKey:o("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectright",description:"Select right",bindKey:o("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoright",description:"Go to right",bindKey:o("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectpagedown",description:"Select page down",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",description:"Page down",bindKey:o(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",description:"Go to page down",bindKey:o("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",description:"Select page up",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",description:"Page up",bindKey:o(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",description:"Go to page up",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",description:"Scroll up",bindKey:o("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",description:"Scroll down",bindKey:o("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",description:"Select line start",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectlineend",description:"Select line end",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"togglerecording",description:"Toggle recording",bindKey:o("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",description:"Replay macro",bindKey:o("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",description:"Jump to matching",bindKey:o("Ctrl-P","Ctrl-P"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"selecttomatching",description:"Select to matching",bindKey:o("Ctrl-Shift-P","Ctrl-Shift-P"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"expandToMatching",description:"Expand to matching",bindKey:o("Ctrl-Shift-M","Ctrl-Shift-M"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"passKeysToBrowser",description:"Pass keys to browser",bindKey:o(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:"copy",description:"Copy",exec:function(e){},readOnly:!0},{name:"cut",description:"Cut",exec:function(e){var t=e.$copyWithEmptySelection&&e.selection.isEmpty(),n=t?e.selection.getLineRange():e.selection.getRange();e._emit("cut",n),n.isEmpty()||e.session.remove(n),e.clearSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"paste",description:"Paste",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:"cursor"},{name:"removeline",description:"Remove line",bindKey:o("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},scrollIntoView:"cursor",multiSelectAction:"forEachLine"},{name:"duplicateSelection",description:"Duplicate selection",bindKey:o("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"sortlines",description:"Sort lines",bindKey:o("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},scrollIntoView:"selection",multiSelectAction:"forEachLine"},{name:"togglecomment",description:"Toggle comment",bindKey:o("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"toggleBlockComment",description:"Toggle block comment",bindKey:o("Ctrl-Shift-/","Command-Shift-/"),exec:function(e){e.toggleBlockComment()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"modifyNumberUp",description:"Modify number up",bindKey:o("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"modifyNumberDown",description:"Modify number down",bindKey:o("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"replace",description:"Replace",bindKey:o("Ctrl-H","Command-Option-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e,!0)})}},{name:"undo",description:"Undo",bindKey:o("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",description:"Redo",bindKey:o("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",description:"Copy lines up",bindKey:o("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()},scrollIntoView:"cursor"},{name:"movelinesup",description:"Move lines up",bindKey:o("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()},scrollIntoView:"cursor"},{name:"copylinesdown",description:"Copy lines down",bindKey:o("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()},scrollIntoView:"cursor"},{name:"movelinesdown",description:"Move lines down",bindKey:o("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()},scrollIntoView:"cursor"},{name:"del",description:"Delete",bindKey:o("Delete","Delete|Ctrl-D|Shift-Delete"),exec:function(e){e.remove("right")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"backspace",description:"Backspace",bindKey:o("Shift-Backspace|Backspace","Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"cut_or_delete",description:"Cut or delete",bindKey:o("Shift-Delete",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestart",description:"Remove to line start",bindKey:o("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineend",description:"Remove to line end",bindKey:o("Alt-Delete","Ctrl-K|Command-Delete"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestarthard",description:"Remove to line start hard",bindKey:o("Ctrl-Shift-Backspace",null),exec:function(e){var t=e.selection.getRange();t.start.column=0,e.session.remove(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineendhard",description:"Remove to line end hard",bindKey:o("Ctrl-Shift-Delete",null),exec:function(e){var t=e.selection.getRange();t.end.column=Number.MAX_VALUE,e.session.remove(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordleft",description:"Remove word left",bindKey:o("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordright",description:"Remove word right",bindKey:o("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"outdent",description:"Outdent",bindKey:o("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"indent",description:"Indent",bindKey:o("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"blockoutdent",description:"Block outdent",bindKey:o("Ctrl-[","Ctrl-["),exec:function(e){e.blockOutdent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"blockindent",description:"Block indent",bindKey:o("Ctrl-]","Ctrl-]"),exec:function(e){e.blockIndent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"insertstring",description:"Insert string",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"inserttext",description:"Insert text",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"splitline",description:"Split line",bindKey:o(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"transposeletters",description:"Transpose letters",bindKey:o("Alt-Shift-X","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:"cursor"},{name:"touppercase",description:"To uppercase",bindKey:o("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"tolowercase",description:"To lowercase",bindKey:o("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"expandtoline",description:"Expand to line",bindKey:o("Ctrl-Shift-L","Command-Shift-L"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"joinlines",description:"Join lines",bindKey:o(null,null),exec:function(e){var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),o=e.session.doc.getLine(n.row).length,u=e.session.doc.getTextRange(e.selection.getRange()),a=u.replace(/\n\s*/," ").length,f=e.session.doc.getLine(n.row);for(var l=n.row+1;l<=i.row+1;l++){var c=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(l)));c.length!==0&&(c=" "+c),f+=c}i.row+10?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+a)):(o=e.session.doc.getLine(n.row).length>o?o+1:o,e.selection.moveCursorTo(n.row,o))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",description:"Invert selection",bindKey:o(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var o=0;o=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:}n=="animate"&&this.renderer.animateScrolling(this.curOp.scrollTop)}var s=this.selection.toJSON();this.curOp.selectionAfter=s,this.$lastSel=this.selection.toJSON(),this.session.getUndoManager().addSelection(s),this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){if(!this.$mergeUndoDeltas)return;var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(e.command.name=="insertstring"){var i=e.args;this.mergeNextCommand===undefined&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\s/.test(i)||/\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&n.indexOf(e.command.name)!==-1;this.$mergeUndoDeltas!="always"&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:n.indexOf(e.command.name)!==-1&&(this.sequenceStartTime=Date.now())},this.setKeyboardHandler=function(e,t){if(e&&typeof e=="string"&&e!="ace"){this.$keybindingId=e;var n=this;g.loadModule(["keybinding",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off("change",this.$onDocumentChange),this.session.off("changeMode",this.$onChangeMode),this.session.off("tokenizerUpdate",this.$onTokenizerUpdate),this.session.off("changeTabSize",this.$onChangeTabSize),this.session.off("changeWrapLimit",this.$onChangeWrapLimit),this.session.off("changeWrapMode",this.$onChangeWrapMode),this.session.off("changeFold",this.$onChangeFold),this.session.off("changeFrontMarker",this.$onChangeFrontMarker),this.session.off("changeBackMarker",this.$onChangeBackMarker),this.session.off("changeBreakpoint",this.$onChangeBreakpoint),this.session.off("changeAnnotation",this.$onChangeAnnotation),this.session.off("changeOverwrite",this.$onCursorChange),this.session.off("changeScrollTop",this.$onScrollTopChange),this.session.off("changeScrollLeft",this.$onScrollLeftChange);var n=this.session.getSelection();n.off("changeCursor",this.$onCursorChange),n.off("changeSelection",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.onCursorChange(),this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal("changeSession",{session:e,oldSession:t}),this.curOp=null,t&&t._signal("changeEditor",{oldEditor:this}),e&&e._signal("changeEditor",{editor:this}),e&&e.bgTokenizer&&e.bgTokenizer.scheduleStart()},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption("fontSize")||i.computedStyle(this.container).fontSize},this.setFontSize=function(e){this.setOption("fontSize",e)},this.$highlightBrackets=function(){this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null);if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=t.findMatchingBracket(e.getCursorPosition());if(n)var r=new p(n.row,n.column,n.row,n.column+1);else if(t.$mode.getMatching)var r=t.$mode.getMatching(e.session);r&&(t.$bracketHighlight=t.addMarker(r,"ace_bracket","text"))},50)},this.$highlightTags=function(){if(this.$highlightTagPending)return;var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=e.getCursorPosition(),r=new y(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\b(?:tag-open|tag-name)/.test(i.type)){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}if(i.type.indexOf("tag-open")!=-1){i=r.stepForward();if(!i)return}var s=i.value,o=0,u=r.stepBackward();if(u.value=="<"){do u=i,i=r.stepForward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="=0)}else{do i=u,u=r.stepBackward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="1)&&(t=!1)}if(e.$highlightLineMarker&&!t)e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null;else if(!e.$highlightLineMarker&&t){var n=new p(t.row,t.column,t.row,Infinity);n.id=e.addMarker(n,"ace_active-line","screenLine"),e.$highlightLineMarker=n}else t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e.$highlightLineMarker.start.column=t.column,e._signal("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column,r=t.end.column,i=e.getLine(t.start.row),s=i.substring(n,r);if(s.length>5e3||!/[\w\d]/.test(s))return;var o=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:s}),u=i.substring(n-1,r+1);if(!o.test(u))return;return o},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit("changeMode",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText(),t=this.session.doc.getNewLineCharacter(),n=!1;if(!e&&this.$copyWithEmptySelection){n=!0;var r=this.selection.getAllRanges();for(var i=0;is.length||i.length<2||!i[1])return this.commands.exec("insertstring",this,t);for(var o=s.length;o--;){var u=s[o];u.isEmpty()||r.remove(u),r.insert(u.start,i[o])}}},this.execCommand=function(e,t){return this.commands.exec(e,this,t)},this.insert=function(e,t){var n=this.session,r=n.getMode(),i=this.getCursorPosition();if(this.getBehavioursEnabled()&&!t){var s=r.transformAction(n.getState(i.row),"insertion",this,n,e);s&&(e!==s.text&&(this.inVirtualSelectionMode||(this.session.mergeUndoDeltas=!1,this.mergeNextCommand=!1)),e=s.text)}e==" "&&(e=this.session.getTabString());if(!this.selection.isEmpty()){var o=this.getSelectionRange();i=this.session.remove(o),this.clearSelection()}else if(this.session.getOverwrite()&&e.indexOf("\n")==-1){var o=new p.fromPoints(i,i);o.end.column+=e.length,this.session.remove(o)}if(e=="\n"||e=="\r\n"){var u=n.getLine(i.row);if(i.column>u.search(/\S|$/)){var a=u.substr(i.column).search(/\S|$/);n.doc.removeInLine(i.row,i.column,i.column+a)}}this.clearSelection();var f=i.column,l=n.getState(i.row),u=n.getLine(i.row),c=r.checkOutdent(l,u,e),h=n.insert(i,e);s&&s.selection&&(s.selection.length==2?this.selection.setSelectionRange(new p(i.row,f+s.selection[0],i.row,f+s.selection[1])):this.selection.setSelectionRange(new p(i.row+s.selection[0],s.selection[1],i.row+s.selection[2],s.selection[3])));if(n.getDocument().isNewLine(e)){var d=r.getNextLineIndent(l,u.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},d)}c&&r.autoOutdent(l,n,i.row)},this.onTextInput=function(e,t){if(!t)return this.keyBinding.onTextInput(e);this.startOperation({command:{name:"insertstring"}});var n=this.applyComposition.bind(this,e,t);this.selection.rangeCount?this.forEachSelection(n):n(),this.endOperation()},this.applyComposition=function(e,t){if(t.extendLeft||t.extendRight){var n=this.selection.getRange();n.start.column-=t.extendLeft,n.end.column+=t.extendRight,this.selection.setRange(n),!e&&!n.isEmpty()&&this.remove()}(e||!this.selection.isEmpty())&&this.insert(e,!0);if(t.restoreStart||t.restoreEnd){var n=this.selection.getRange();n.start.column-=t.restoreStart,n.end.column-=t.restoreEnd,this.selection.setRange(n)}},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption("scrollSpeed",e)},this.getScrollSpeed=function(){return this.getOption("scrollSpeed")},this.setDragDelay=function(e){this.setOption("dragDelay",e)},this.getDragDelay=function(){return this.getOption("dragDelay")},this.setSelectionStyle=function(e){this.setOption("selectionStyle",e)},this.getSelectionStyle=function(){return this.getOption("selectionStyle")},this.setHighlightActiveLine=function(e){this.setOption("highlightActiveLine",e)},this.getHighlightActiveLine=function(){return this.getOption("highlightActiveLine")},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.setHighlightSelectedWord=function(e){this.setOption("highlightSelectedWord",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption("readOnly",e)},this.getReadOnly=function(){return this.getOption("readOnly")},this.setBehavioursEnabled=function(e){this.setOption("behavioursEnabled",e)},this.getBehavioursEnabled=function(){return this.getOption("behavioursEnabled")},this.setWrapBehavioursEnabled=function(e){this.setOption("wrapBehavioursEnabled",e)},this.getWrapBehavioursEnabled=function(){return this.getOption("wrapBehavioursEnabled")},this.setShowFoldWidgets=function(e){this.setOption("showFoldWidgets",e)},this.getShowFoldWidgets=function(){return this.getOption("showFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);if(t.end.column===0){var s=n.getTextRange(t);if(s[s.length-1]=="\n"){var o=n.getLine(t.end.row);/^\s+$/.test(o)&&(t.end.column=o.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.selection.isEmpty()&&this.selection.selectLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;tt.toLowerCase()?1:0});var i=new p(0,0,0,0);for(var r=e.first;r<=e.last;r++){var s=t.getLine(r);i.start.row=r,i.end.row=r,i.end.column=s.length,t.replace(i,n[r-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&n=u&&o<=a&&(n=t,f.selection.clearSelection(),f.moveCursorTo(e,u+r),f.selection.selectTo(e,a+r)),u=a});var l=this.$toggleWordPairs,c;for(var h=0;hp+1)break;p=d.last}l--,u=this.session.$moveLines(h,p,t?0:e),t&&e==-1&&(c=l+1);while(c<=l)o[c].moveBy(u,0),c++;t||(u=0),a+=u}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(e)},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);t===!0?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t===!1&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection());var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.selection.selectAll()},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new y(this.session,n.row,n.column),i=r.getCurrentToken(),s=i||r.stepForward();if(!s)return;var o,u=!1,a={},f=n.column-s.start,l,c={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(s.value.match(/[{}()\[\]]/g))for(;f=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.session.unfold(e),this.selection.setSelectionRange(e);var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!==!1&&this.renderer.animateScrolling(n)},this.undo=function(){this.session.getUndoManager().undo(this.session),this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.session.getUndoManager().redo(this.session),this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy(),this._signal("destroy",this),this.session&&this.session.destroy()},this.setAutoScrollEditorIntoView=function(e){if(!e)return;var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement("div"));var i=this.$scrollAnchor;i.style.cssText="position:absolute",this.container.insertBefore(i,this.container.firstChild);var s=this.on("changeSelection",function(){r=!0}),o=this.renderer.on("beforeRender",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),u=this.renderer.on("afterRender",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,s=e.$cursorLayer.$pixelPos,o=e.layerConfig,u=s.top-o.offset;s.top>=0&&u+t.top<0?r=!0:s.topwindow.innerHeight?r=!1:r=null,r!=null&&(i.style.top=u+"px",i.style.left=s.left+"px",i.style.height=o.lineHeight+"px",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){if(e)return;delete this.setAutoScrollEditorIntoView,this.off("changeSelection",s),this.renderer.off("afterRender",u),this.renderer.off("beforeRender",o)}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;if(!t)return;t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&e!="wide",i.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e))},this.prompt=function(e,t,n){var r=this;g.loadModule("./ext/prompt",function(i){i.prompt(r,e,t,n)})}}.call(w.prototype),g.defineOptions(w.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.textInput.setReadOnly(e),this.$resetCursorStyle()},initialValue:!1},copyWithEmptySelection:{set:function(e){this.textInput.setCopyWithEmptySelection(e)},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.$keybindingId},handlesSet:!0},value:{set:function(e){this.session.setValue(e)},get:function(){return this.getValue()},handlesSet:!0,hidden:!0},session:{set:function(e){this.setSession(e)},get:function(){return this.session},handlesSet:!0,hidden:!0},showLineNumbers:{set:function(e){this.renderer.$gutterLayer.setShowLineNumbers(e),this.renderer.$loop.schedule(this.renderer.CHANGE_GUTTER),e&&this.$relativeLineNumbers?E.attach(this):E.detach(this)},initialValue:!0},relativeLineNumbers:{set:function(e){this.$showLineNumbers&&e?E.attach(this):E.detach(this)}},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",displayIndentGuides:"renderer",showGutter:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",hasCssTransforms:"renderer",maxPixelHeight:"renderer",useTextareaForIME:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimeout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",navigateWithinSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"});var E={getText:function(e,t){return(Math.abs(e.selection.lead.row-t)||t+1+(t<9?"\u00b7":""))+""},getWidth:function(e,t,n){return Math.max(t.toString().length,(n.lastRow+1).toString().length,2)*n.characterWidth},update:function(e,t){t.renderer.$loop.schedule(t.renderer.CHANGE_GUTTER)},attach:function(e){e.renderer.$gutterLayer.$renderer=this,e.on("changeSelection",this.update),this.update(null,e)},detach:function(e){e.renderer.$gutterLayer.$renderer==this&&(e.renderer.$gutterLayer.$renderer=null),e.off("changeSelection",this.update),this.update(null,e)}};t.Editor=w}),ace.define("ace/undomanager",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){for(var n=t;n--;){var r=e[n];if(r&&!r[0].ignore){while(n0){a.row+=i,a.column+=a.row==r.row?s:0;continue}!t&&l<=0&&(a.row=n.row,a.column=n.column,l===0&&(a.bias=1))}}function f(e){return{row:e.row,column:e.column}}function l(e){return{start:f(e.start),end:f(e.end),action:e.action,lines:e.lines.slice()}}function c(e){e=e||this;if(Array.isArray(e))return e.map(c).join("\n");var t="";e.action?(t=e.action=="insert"?"+":"-",t+="["+e.lines+"]"):e.value&&(Array.isArray(e.value)?t=e.value.map(h).join("\n"):t=h(e.value)),e.start&&(t+=h(e));if(e.id||e.rev)t+=" ("+(e.id||e.rev)+")";return t}function h(e){return e.start.row+":"+e.start.column+"=>"+e.end.row+":"+e.end.column}function p(e,t){var n=e.action=="insert",r=t.action=="insert";if(n&&r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.start,e.start)<=0))return null;m(e,t,1)}else if(n&&!r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.end,e.start)<=0))return null;m(e,t,-1)}else if(!n&&r)if(o(t.start,e.start)>=0)m(t,e,1);else{if(!(o(t.start,e.start)<=0))return null;m(e,t,1)}else if(!n&&!r)if(o(t.start,e.start)>=0)m(t,e,1);else{if(!(o(t.end,e.start)<=0))return null;m(e,t,-1)}return[t,e]}function d(e,t){for(var n=e.length;n--;)for(var r=0;r=0?m(e,t,-1):o(e.start,t.start)<=0?m(t,e,1):(m(e,s.fromPoints(t.start,e.start),-1),m(t,e,1));else if(!n&&r)o(t.start,e.end)>=0?m(t,e,-1):o(t.start,e.start)<=0?m(e,t,1):(m(t,s.fromPoints(e.start,t.start),-1),m(e,t,1));else if(!n&&!r)if(o(t.start,e.end)>=0)m(t,e,-1);else{if(!(o(t.end,e.start)<=0)){var i,u;return o(e.start,t.start)<0&&(i=e,e=y(e,t.start)),o(e.end,t.end)>0&&(u=y(e,t.end)),g(t.end,e.start,e.end,-1),u&&!i&&(e.lines=u.lines,e.start=u.start,e.end=u.end,u=e),[t,i,u].filter(Boolean)}m(e,t,-1)}return[t,e]}function m(e,t,n){g(e.start,t.start,t.end,n),g(e.end,t.start,t.end,n)}function g(e,t,n,r){e.row==(r==1?t:n).row&&(e.column+=r*(n.column-t.column)),e.row+=r*(n.row-t.row)}function y(e,t){var n=e.lines,r=e.end;e.end=f(t);var i=e.end.row-e.start.row,s=n.splice(i,n.length),o=i?t.column:t.column-e.start.column;n.push(s[0].substring(0,o)),s[0]=s[0].substr(o);var u={start:f(t),end:r,lines:s,action:e.action};return u}function b(e,t){t=l(t);for(var n=e.length;n--;){var r=e[n];for(var i=0;i0},this.canRedo=function(){return this.$redoStack.length>0},this.bookmark=function(e){e==undefined&&(e=this.$rev),this.mark=e},this.isAtBookmark=function(){return this.$rev===this.mark},this.toJSON=function(){},this.fromJSON=function(){},this.hasUndo=this.canUndo,this.hasRedo=this.canRedo,this.isClean=this.isAtBookmark,this.markClean=this.bookmark,this.$prettyPrint=function(e){return e?c(e):c(this.$undoStack)+"\n---\n"+c(this.$redoStack)}}).call(r.prototype);var s=e("./range").Range,o=s.comparePoints,u=s.comparePoints;t.UndoManager=r}),ace.define("ace/layer/lines",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=function(e,t){this.element=e,this.canvasHeight=t||5e5,this.element.style.height=this.canvasHeight*2+"px",this.cells=[],this.cellCache=[],this.$offsetCoefficient=0};(function(){this.moveContainer=function(e){r.translate(this.element,0,-(e.firstRowScreen*e.lineHeight%this.canvasHeight)-e.offset*this.$offsetCoefficient)},this.pageChanged=function(e,t){return Math.floor(e.firstRowScreen*e.lineHeight/this.canvasHeight)!==Math.floor(t.firstRowScreen*t.lineHeight/this.canvasHeight)},this.computeLineTop=function(e,t,n){var r=t.firstRowScreen*t.lineHeight,i=Math.floor(r/this.canvasHeight),s=n.documentToScreenRow(e,0)*t.lineHeight;return s-i*this.canvasHeight},this.computeLineHeight=function(e,t,n){return t.lineHeight*n.getRowLength(e)},this.getLength=function(){return this.cells.length},this.get=function(e){return this.cells[e]},this.shift=function(){this.$cacheCell(this.cells.shift())},this.pop=function(){this.$cacheCell(this.cells.pop())},this.push=function(e){if(Array.isArray(e)){this.cells.push.apply(this.cells,e);var t=r.createFragment(this.element);for(var n=0;ns&&(a=i.end.row+1,i=t.getNextFoldLine(a,i),s=i?i.start.row:Infinity);if(a>r){while(this.$lines.getLength()>u+1)this.$lines.pop();break}o=this.$lines.get(++u),o?o.row=a:(o=this.$lines.createCell(a,e,this.session,f),this.$lines.push(o)),this.$renderCell(o,e,i,a),a++}this._signal("afterRender"),this.$updateGutterWidth(e)},this.$updateGutterWidth=function(e){var t=this.session,n=t.gutterRenderer||this.$renderer,r=t.$firstLineNumber,i=this.$lines.last()?this.$lines.last().text:"";if(this.$fixedWidth||t.$useWrapMode)i=t.getLength()+r-1;var s=n?n.getWidth(t,i,e):i.toString().length*e.characterWidth,o=this.$padding||this.$computePadding();s+=o.left+o.right,s!==this.gutterWidth&&!isNaN(s)&&(this.gutterWidth=s,this.element.parentNode.style.width=this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._signal("changeGutterWidth",s))},this.$updateCursorRow=function(){if(!this.$highlightGutterLine)return;var e=this.session.selection.getCursor();if(this.$cursorRow===e.row)return;this.$cursorRow=e.row},this.updateLineHighlight=function(){if(!this.$highlightGutterLine)return;var e=this.session.selection.cursor.row;this.$cursorRow=e;if(this.$cursorCell&&this.$cursorCell.row==e)return;this.$cursorCell&&(this.$cursorCell.element.className=this.$cursorCell.element.className.replace("ace_gutter-active-line ",""));var t=this.$lines.cells;this.$cursorCell=null;for(var n=0;n=this.$cursorRow){if(r.row>this.$cursorRow){var i=this.session.getFoldLine(this.$cursorRow);if(!(n>0&&i&&i.start.row==t[n-1].row))break;r=t[n-1]}r.element.className="ace_gutter-active-line "+r.element.className,this.$cursorCell=r;break}}},this.scrollLines=function(e){var t=this.config;this.config=e,this.$updateCursorRow();if(this.$lines.pageChanged(t,e))return this.update(e);this.$lines.moveContainer(e);var n=Math.min(e.lastRow+e.gutterOffset,this.session.getLength()-1),r=this.oldLastRow;this.oldLastRow=n;if(!t||r0;i--)this.$lines.shift();if(r>n)for(var i=this.session.getFoldedRowCount(n+1,r);i>0;i--)this.$lines.pop();e.firstRowr&&this.$lines.push(this.$renderLines(e,r+1,n)),this.updateLineHighlight(),this._signal("afterRender"),this.$updateGutterWidth(e)},this.$renderLines=function(e,t,n){var r=[],i=t,s=this.session.getNextFoldLine(i),o=s?s.start.row:Infinity;for(;;){i>o&&(i=s.end.row+1,s=this.session.getNextFoldLine(i,s),o=s?s.start.row:Infinity);if(i>n)break;var u=this.$lines.createCell(i,e,this.session,f);this.$renderCell(u,e,s,i),r.push(u),i++}return r},this.$renderCell=function(e,t,n,i){var s=e.element,o=this.session,u=s.childNodes[0],a=s.childNodes[1],f=o.$firstLineNumber,l=o.$breakpoints,c=o.$decorations,h=o.gutterRenderer||this.$renderer,p=this.$showFoldWidgets&&o.foldWidgets,d=n?n.start.row:Number.MAX_VALUE,v="ace_gutter-cell ";this.$highlightGutterLine&&(i==this.$cursorRow||n&&i=d&&this.$cursorRow<=n.end.row)&&(v+="ace_gutter-active-line ",this.$cursorCell!=e&&(this.$cursorCell&&(this.$cursorCell.element.className=this.$cursorCell.element.className.replace("ace_gutter-active-line ","")),this.$cursorCell=e)),l[i]&&(v+=l[i]),c[i]&&(v+=c[i]),this.$annotations[i]&&(v+=this.$annotations[i].className),s.className!=v&&(s.className=v);if(p){var m=p[i];m==null&&(m=p[i]=o.getFoldWidget(i))}if(m){var v="ace_fold-widget ace_"+m;m=="start"&&i==d&&in.right-t.right)return"foldWidgets"}}).call(a.prototype),t.Gutter=a}),ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.elt=function(e,t){var n=this.i!=-1&&this.element.childNodes[this.i];n?this.i++:(n=document.createElement("div"),this.element.appendChild(n),this.i=-1),n.style.cssText=t,n.className=e},this.update=function(e){if(!e)return;this.config=e,this.i=0;var t;for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var i=r.range.clipRows(e.firstRow,e.lastRow);if(i.isEmpty())continue;i=i.toScreenRange(this.session);if(r.renderer){var s=this.$getTop(i.start.row,e),o=this.$padding+i.start.column*e.characterWidth;r.renderer(t,i,o,s,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,i,r.clazz,e):r.type=="screenLine"?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?r.type=="text"?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.drawSingleLineMarker(t,i,r.clazz+" ace_start"+" ace_br15",e)}if(this.i!=-1)while(this.ip,l==f),s,l==f?0:1,o)},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;i=i||"";if(this.session.$bidiHandler.isBidiRow(t.start.row)){var f=t.clone();f.end.row=f.start.row,f.end.column=this.session.getLine(f.start.row).length,this.drawBidiSingleLineMarker(e,f,n+" ace_br1 ace_start",r,null,i)}else this.elt(n+" ace_br1 ace_start","height:"+o+"px;"+"right:0;"+"top:"+u+"px;left:"+a+"px;"+(i||""));if(this.session.$bidiHandler.isBidiRow(t.end.row)){var f=t.clone();f.start.row=f.end.row,f.start.column=0,this.drawBidiSingleLineMarker(e,f,n+" ace_br12",r,null,i)}else{u=this.$getTop(t.end.row,r);var l=t.end.column*r.characterWidth;this.elt(n+" ace_br12","height:"+o+"px;"+"width:"+l+"px;"+"top:"+u+"px;"+"left:"+s+"px;"+(i||""))}o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<=0)return;u=this.$getTop(t.start.row+1,r);var c=(t.start.column?1:0)|(t.end.column?0:8);this.elt(n+(c?" ace_br"+c:""),"height:"+o+"px;"+"right:0;"+"top:"+u+"px;"+"left:"+s+"px;"+(i||""))},this.drawSingleLineMarker=function(e,t,n,r,i,s){if(this.session.$bidiHandler.isBidiRow(t.start.row))return this.drawBidiSingleLineMarker(e,t,n,r,i,s);var o=r.lineHeight,u=(t.end.column+(i||0)-t.start.column)*r.characterWidth,a=this.$getTop(t.start.row,r),f=this.$padding+t.start.column*r.characterWidth;this.elt(n,"height:"+o+"px;"+"width:"+u+"px;"+"top:"+a+"px;"+"left:"+f+"px;"+(s||""))},this.drawBidiSingleLineMarker=function(e,t,n,r,i,s){var o=r.lineHeight,u=this.$getTop(t.start.row,r),a=this.$padding,f=this.session.$bidiHandler.getSelections(t.start.column,t.end.column);f.forEach(function(e){this.elt(n,"height:"+o+"px;"+"width:"+e.width+(i||0)+"px;"+"top:"+u+"px;"+"left:"+(a+e.left)+"px;"+(s||""))},this)},this.drawFullLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;t.start.row!=t.end.row&&(o+=this.$getTop(t.end.row,r)-s),this.elt(n,"height:"+o+"px;"+"top:"+s+"px;"+"left:0;right:0;"+(i||""))},this.drawScreenLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;this.elt(n,"height:"+o+"px;"+"top:"+s+"px;"+"left:0;right:0;"+(i||""))}}).call(s.prototype),t.Marker=s}),ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/layer/lines","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("./lines").Lines,u=e("../lib/event_emitter").EventEmitter,a=function(e){this.dom=i,this.element=this.dom.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this),this.$lines=new o(this.element)};(function(){r.implement(this,u),this.EOF_CHAR="\u00b6",this.EOL_CHAR_LF="\u00ac",this.EOL_CHAR_CRLF="\u00a4",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR="\u2014",this.SPACE_CHAR="\u00b7",this.$padding=0,this.MAX_LINE_LENGTH=1e4,this.$updateEolChar=function(){var e=this.session.doc,t=e.getNewLineCharacter()=="\n"&&e.getNewLineMode()!="windows",n=t?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=n)return this.EOL_CHAR=n,!0},this.setPadding=function(e){this.$padding=e,this.element.style.margin="0 "+e+"px"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on("changeCharacterSize",function(e){this._signal("changeCharacterSize",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;nl&&(u=a.end.row+1,a=this.session.getNextFoldLine(u,a),l=a?a.start.row:Infinity);if(u>i)break;var c=s[o++];if(c){this.dom.removeChildren(c),this.$renderLine(c,u,u==l?a:!1);var h=e.lineHeight*this.session.getRowLength(u)+"px";c.style.height!=h&&(f=!0,c.style.height=h)}u++}if(f)while(o0;i--)this.$lines.shift();if(t.lastRow>e.lastRow)for(var i=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);i>0;i--)this.$lines.pop();e.firstRowt.lastRow&&this.$lines.push(this.$renderLinesFragment(e,t.lastRow+1,e.lastRow))},this.$renderLinesFragment=function(e,t,n){var r=[],s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=this.$lines.createCell(s,e,this.session),f=a.element;this.dom.removeChildren(f),i.setStyle(f.style,"height",this.$lines.computeLineHeight(s,e,this.session)+"px"),i.setStyle(f.style,"top",this.$lines.computeLineTop(s,e,this.session)+"px"),this.$renderLine(f,s,s==u?o:!1),this.$useLineGroups()?f.className="ace_line_group":f.className="ace_line",r.push(a),s++}return r},this.update=function(e){this.$lines.moveContainer(e),this.config=e;var t=e.firstRow,n=e.lastRow,r=this.$lines;while(r.getLength())r.pop();r.push(this.$renderLinesFragment(e,t,n))},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,o=/(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g,u=this.dom.createFragment(this.element),a,f=0;while(a=o.exec(r)){var l=a[1],c=a[2],h=a[3],p=a[4],d=a[5];if(!i.showInvisibles&&c)continue;var v=f!=a.index?r.slice(f,a.index):"";f=a.index+a[0].length,v&&u.appendChild(this.dom.createTextNode(v,this.element));if(l){var m=i.session.getScreenTabSize(t+a.index);u.appendChild(i.$tabStrings[m].cloneNode(!0)),t+=m-1}else if(c)if(i.showInvisibles){var g=this.dom.createElement("span");g.className="ace_invisible ace_invisible_space",g.textContent=s.stringRepeat(i.SPACE_CHAR,c.length),u.appendChild(g)}else u.appendChild(this.com.createTextNode(c,this.element));else if(h){var g=this.dom.createElement("span");g.className="ace_invisible ace_invisible_space ace_invalid",g.textContent=s.stringRepeat(i.SPACE_CHAR,h.length),u.appendChild(g)}else if(p){var y=i.showInvisibles?i.SPACE_CHAR:"";t+=1;var g=this.dom.createElement("span");g.style.width=i.config.characterWidth*2+"px",g.className=i.showInvisibles?"ace_cjk ace_invisible ace_invisible_space":"ace_cjk",g.textContent=i.showInvisibles?i.SPACE_CHAR:"",u.appendChild(g)}else if(d){t+=1;var g=this.dom.createElement("span");g.style.width=i.config.characterWidth*2+"px",g.className="ace_cjk",g.textContent=d,u.appendChild(g)}}u.appendChild(this.dom.createTextNode(f?r.slice(f):r,this.element));if(!this.$textToken[n.type]){var b="ace_"+n.type.replace(/\./g," ace_"),g=this.dom.createElement("span");n.type=="fold"&&(g.style.width=n.value.length*this.config.characterWidth+"px"),g.className=b,g.appendChild(u),e.appendChild(g)}else e.appendChild(u);return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);if(r<=0||r>=n)return t;if(t[0]==" "){r-=r%this.tabSize;var i=r/this.tabSize;for(var s=0;s=o)u=this.$renderToken(a,u,l,c.substring(0,o-r)),c=c.substring(o-r),r=o,a=this.$createLineElement(),e.appendChild(a),a.appendChild(this.dom.createTextNode(s.stringRepeat("\u00a0",n.indent),this.element)),i++,u=0,o=n[i]||Number.MAX_VALUE;c.length!=0&&(r+=c.length,u=this.$renderToken(a,u,l,c))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;sthis.MAX_LINE_LENGTH)return this.$renderOverflowMessage(e,n,r,i);n=this.$renderToken(e,n,r,i)}},this.$renderOverflowMessage=function(e,t,n,r){this.$renderToken(e,t,n,r.slice(0,this.MAX_LINE_LENGTH-t));var i=this.dom.createElement("span");i.className="ace_inline_button ace_keyword ace_toggle_wrap",i.style.position="absolute",i.style.right="0",i.textContent="",e.appendChild(i)},this.$renderLine=function(e,t,n){!n&&n!=0&&(n=this.session.getFoldLine(t));if(n)var r=this.$getFoldLineTokens(t,n);else var r=this.session.getTokens(t);var i=e;if(r.length){var s=this.session.getRowSplitData(t);if(s&&s.length){this.$renderWrappedLine(e,r,s);var i=e.lastChild}else{var i=e;this.$useLineGroups()&&(i=this.$createLineElement(),e.appendChild(i)),this.$renderSimpleLine(i,r)}}else this.$useLineGroups()&&(i=this.$createLineElement(),e.appendChild(i));if(this.showInvisibles&&i){n&&(t=n.end.row);var o=this.dom.createElement("span");o.className="ace_invisible ace_invisible_eol",o.textContent=t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,i.appendChild(o)}},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.lengthn-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(sn?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){}}).call(a.prototype),t.Text=a}),ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=this.$updateOpacity.bind(this)};(function(){this.$updateOpacity=function(e){var t=this.cursors;for(var n=t.length;n--;)r.setStyle(t[n].style,"opacity",e?"":"0")},this.$startCssAnimation=function(){var e=this.cursors;for(var t=e.length;t--;)e[t].style.animationDuration=this.blinkInterval+"ms";setTimeout(function(){r.addCssClass(this.element,"ace_animate-blinking")}.bind(this))},this.$stopCssAnimation=function(){r.removeCssClass(this.element,"ace_animate-blinking")},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&(this.smoothBlinking=e,r.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.$stopCssAnimation(),this.smoothBlinking&&r.removeCssClass(this.element,"ace_smooth-blinking"),e(!0);if(!this.isBlinking||!this.blinkInterval||!this.isVisible){this.$stopCssAnimation();return}this.smoothBlinking&&setTimeout(function(){r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this));if(r.HAS_CSS_ANIMATION)this.$startCssAnimation();else{var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()}},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+(this.session.$bidiHandler.isBidiRow(n.row,e.row)?this.session.$bidiHandler.getPosLeft(n.column):n.column*this.config.characterWidth),i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.isCursorInView=function(e,t){return e.top>=0&&e.tope.height+e.offset||o.top<0)&&n>1)continue;var u=this.cursors[i++]||this.addCursor(),a=u.style;this.drawCursor?this.drawCursor(u,o,e,t[n],this.session):this.isCursorInView(o,e)?(r.setStyle(a,"display","block"),r.translate(u,o.left,o.top),r.setStyle(a,"width",Math.round(e.characterWidth)+"px"),r.setStyle(a,"height",e.lineHeight+"px")):r.setStyle(a,"display","none")}while(this.cursors.length>i)this.removeCursor();var f=this.session.getOverwrite();this.$setOverwrite(f),this.$pixelPos=o,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(i.prototype),t.Cursor=i}),ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=32768,a=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,s.addListener(this.element,"scroll",this.onScroll.bind(this)),s.addListener(this.element,"mousedown",s.preventDefault)};(function(){r.implement(this,o),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e,this.coeff=1}}).call(a.prototype);var f=function(e,t){a.call(this,e),this.scrollTop=0,this.scrollHeight=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px",this.$minWidth=0};r.inherits(f,a),function(){this.classSuffix="-v",this.onScroll=function(){if(!this.skipEvent){this.scrollTop=this.element.scrollTop;if(this.coeff!=1){var e=this.element.clientHeight/this.scrollHeight;this.scrollTop=this.scrollTop*(1-e)/(this.coeff-e)}this._emit("scroll",{data:this.scrollTop})}this.skipEvent=!1},this.getWidth=function(){return Math.max(this.isVisible?this.width:0,this.$minWidth||0)},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=this.setScrollHeight=function(e){this.scrollHeight=e,e>u?(this.coeff=u/e,e=u):this.coeff!=1&&(this.coeff=1),this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=e,this.element.scrollTop=e*this.coeff)}}.call(f.prototype);var l=function(e,t){a.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"};r.inherits(l,a),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(l.prototype),t.ScrollBar=f,t.ScrollBarV=f,t.ScrollBarH=l,t.VScrollBar=f,t.HScrollBar=l}),ace.define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){"use strict";var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.$recursionLimit=2,this.window=t||window;var n=this;this._flush=function(e){n.pending=!1;var t=n.changes;t&&(r.blockIdle(100),n.changes=0,n.onRender(t));if(n.changes){if(n.$recursionLimit--<0)return;n.schedule()}else n.$recursionLimit=2}};(function(){this.schedule=function(e){this.changes=this.changes|e,this.changes&&!this.pending&&(r.nextFrame(this._flush),this.pending=!0)},this.clear=function(e){var t=this.changes;return this.changes=0,t}}).call(i.prototype),t.RenderLoop=i}),ace.define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/event"),u=e("../lib/useragent"),a=e("../lib/event_emitter").EventEmitter,f=256,l=typeof ResizeObserver=="function",c=200,h=t.FontMetrics=function(e){this.el=i.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),this.$measureNode.innerHTML=s.stringRepeat("X",f),this.$characterSize={width:0,height:0},l?this.$addObserver():this.checkForSizeChanges()};(function(){r.implement(this,a),this.$characterSize={width:0,height:0},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",u.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(e){e===undefined&&(e=this.$measureSizes());if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$addObserver=function(){var e=this;this.$observer=new window.ResizeObserver(function(t){var n=t[0].contentRect;e.checkForSizeChanges({height:n.height,width:n.width/f})}),this.$observer.observe(this.$measureNode)},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer||this.$observer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=o.onIdle(function t(){e.checkForSizeChanges(),o.onIdle(t,500)},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(e){var t={height:(e||this.$measureNode).clientHeight,width:(e||this.$measureNode).clientWidth/f};return t.width===0||t.height===0?null:t},this.$measureCharWidth=function(e){this.$main.innerHTML=s.stringRepeat(e,f);var t=this.$main.getBoundingClientRect();return t.width/f},this.getCharacterWidth=function(e){var t=this.charSizes[e];return t===undefined&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$observer&&this.$observer.disconnect(),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)},this.$getZoom=function e(t){return t?(window.getComputedStyle(t).zoom||1)*e(t.parentElement):1},this.$initTransformMeasureNodes=function(){var e=function(e,t){return["div",{style:"position: absolute;top:"+e+"px;left:"+t+"px;"}]};this.els=i.buildDom([e(0,0),e(c,0),e(0,c),e(c,c)],this.el)},this.transformCoordinates=function(e,t){function r(e,t,n){var r=e[1]*t[0]-e[0]*t[1];return[(-t[1]*n[0]+t[0]*n[1])/r,(+e[1]*n[0]-e[0]*n[1])/r]}function i(e,t){return[e[0]-t[0],e[1]-t[1]]}function s(e,t){return[e[0]+t[0],e[1]+t[1]]}function o(e,t){return[e*t[0],e*t[1]]}function u(e){var t=e.getBoundingClientRect();return[t.left,t.top]}if(e){var n=this.$getZoom(this.el);e=o(1/n,e)}this.els||this.$initTransformMeasureNodes();var a=u(this.els[0]),f=u(this.els[1]),l=u(this.els[2]),h=u(this.els[3]),p=r(i(h,f),i(h,l),i(s(f,l),s(h,a))),d=o(1+p[0],i(f,a)),v=o(1+p[1],i(l,a));if(t){var m=t,g=p[0]*m[0]/c+p[1]*m[1]/c+1,y=s(o(m[0],d),o(m[1],v));return s(o(1/g/c,y),a)}var b=i(e,a),w=r(i(d,o(p[0],b)),i(v,o(p[1],b)),b);return o(c,w)}}).call(h.prototype)}),ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./config"),o=e("./layer/gutter").Gutter,u=e("./layer/marker").Marker,a=e("./layer/text").Text,f=e("./layer/cursor").Cursor,l=e("./scrollbar").HScrollBar,c=e("./scrollbar").VScrollBar,h=e("./renderloop").RenderLoop,p=e("./layer/font_metrics").FontMetrics,d=e("./lib/event_emitter").EventEmitter,v='.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_editor {position: relative;overflow: hidden;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;box-sizing: border-box;min-width: 100%;contain: style size layout;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;contain: style size layout;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {position: absolute;top: 0;left: 0;right: 0;padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {contain: strict;position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;contain: strict;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: transparent;color: inherit;z-index: 1000;opacity: 1;}.ace_composition_placeholder { color: transparent }.ace_composition_marker { border-bottom: 1px solid;position: absolute;border-radius: 0;margin-top: 1px;}[ace_nocontext=true] {transform: none!important;filter: none!important;perspective: none!important;clip-path: none!important;mask : none!important;contain: none!important;perspective: none!important;mix-blend-mode: initial!important;z-index: auto;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;height: 1000000px;contain: style size layout;}.ace_text-layer {font: inherit !important;position: absolute;height: 1000000px;width: 1000000px;contain: style size layout;}.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {contain: style size layout;position: absolute;top: 0;left: 0;right: 0;}.ace_hidpi .ace_text-layer,.ace_hidpi .ace_gutter-layer,.ace_hidpi .ace_content,.ace_hidpi .ace_gutter {contain: strict;will-change: transform;}.ace_hidpi .ace_text-layer > .ace_line, .ace_hidpi .ace_text-layer > .ace_line_group {contain: strict;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {transition: opacity 0.18s;}.ace_animate-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: step-end;animation-name: blink-ace-animate;animation-iteration-count: infinite;}.ace_animate-blinking.ace_smooth-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: ease-in-out;animation-name: blink-ace-animate-smooth;}@keyframes blink-ace-animate {from, to { opacity: 1; }60% { opacity: 0; }}@keyframes blink-ace-animate-smooth {from, to { opacity: 1; }45% { opacity: 1; }60% { opacity: 0; }85% { opacity: 0; }}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;box-sizing: border-box;}.ace_line .ace_fold {box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block; }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_inline_button {border: 1px solid lightgray;display: inline-block;margin: -1px 8px;padding: 0 5px;pointer-events: auto;cursor: pointer;}.ace_inline_button:hover {border-color: gray;background: rgba(200,200,200,0.2);display: inline-block;pointer-events: auto;}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}',m=e("./lib/useragent"),g=m.isIE;i.importCssString(v,"ace_editor.css");var y=function(e,t){var n=this;this.container=e||i.createElement("div"),i.addCssClass(this.container,"ace_editor"),i.HI_DPI&&i.addCssClass(this.container,"ace_hidpi"),this.setTheme(t),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.$gutter.setAttribute("aria-hidden",!0),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new o(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new u(this.content);var r=this.$textLayer=new a(this.content);this.canvas=r.element,this.$markerFront=new u(this.content),this.$cursorLayer=new f(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new c(this.container,this),this.scrollBarH=new l(this.container,this),this.scrollBarV.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new p(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.addEventListener("changeCharacterSize",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.margin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$keepTextAreaAtCursor=!m.isIOS,this.$loop=new h(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),s.resetOptions(this),s._emit("renderer",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,d),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e);if(!e)return;this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.scrollBarH.scrollLeft=this.scrollBarV.scrollTop=null,this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode)},this.updateLines=function(e,t,n){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRowthis.layerConfig.lastRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar(),this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR)},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(this.resizing>2)return;this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var s=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(s|this.$changes,!0):this.$loop.schedule(s|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarV.scrollLeft=this.scrollBarV.scrollTop=null},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var s=0,o=this.$size,u={width:o.width,height:o.height,scrollerHeight:o.scrollerHeight,scrollerWidth:o.scrollerWidth};r&&(e||o.height!=r)&&(o.height=r,s|=this.CHANGE_SIZE,o.scrollerHeight=o.height,this.$horizScroll&&(o.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+"px",s|=this.CHANGE_SCROLL);if(n&&(e||o.width!=n)){s|=this.CHANGE_SIZE,o.width=n,t==null&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,i.setStyle(this.scrollBarH.element.style,"left",t+"px"),i.setStyle(this.scroller.style,"left",t+this.margin.left+"px"),o.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()-this.margin.h),i.setStyle(this.$gutter.style,"left",this.margin.left+"px");var a=this.scrollBarV.getWidth()+"px";i.setStyle(this.scrollBarH.element.style,"right",a),i.setStyle(this.scroller.style,"right",a),i.setStyle(this.scroller.style,"bottom",this.scrollBarH.getHeight());if(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)s|=this.CHANGE_FULL}return o.$dirty=!n||!r,s&&this._signal("resize",u),s},this.onGutterResize=function(e){var t=this.$showGutter?e:0;t!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,t,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):this.$computeLayerConfig()},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption("animatedScroll",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption("showInvisibles",e),this.session.$bidiHandler.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.getOption("showInvisibles")},this.getDisplayIndentGuides=function(){return this.getOption("displayIndentGuides")},this.setDisplayIndentGuides=function(e){this.setOption("displayIndentGuides",e)},this.setShowPrintMargin=function(e){this.setOption("showPrintMargin",e)},this.getShowPrintMargin=function(){return this.getOption("showPrintMargin")},this.setPrintMarginColumn=function(e){this.setOption("printMarginColumn",e)},this.getPrintMarginColumn=function(){return this.getOption("printMarginColumn")},this.getShowGutter=function(){return this.getOption("showGutter")},this.setShowGutter=function(e){return this.setOption("showGutter",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=Math.round(this.characterWidth*this.$printMarginColumn+this.$padding)+"px",t.visibility=this.$showPrintMargin?"visible":"hidden",this.session&&this.session.$wrap==-1&&this.adjustWrapLimit()},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){var e=this.textarea.style;if(!this.$keepTextAreaAtCursor){i.translate(this.textarea,-100,0);return}var t=this.$cursorLayer.$pixelPos;if(!t)return;var n=this.$composition;n&&n.markerRange&&(t=this.$cursorLayer.getPixelPosition(n.markerRange.start,!0));var r=this.layerConfig,s=t.top,o=t.left;s-=r.offset;var u=n&&n.useTextareaForIME?this.lineHeight:g?0:1;if(s<0||s>r.height-u){i.translate(this.textarea,0,0);return}var a=1;if(!n)s+=this.lineHeight;else if(n.useTextareaForIME){var f=this.textarea.value;a=this.characterWidth*this.session.$getStringScreenWidth(f)[0],u+=2}else s+=this.lineHeight+2;o-=this.scrollLeft,o>this.$size.scrollerWidth-a&&(o=this.$size.scrollerWidth-a),o+=this.gutterWidth+this.margin.left,i.setStyle(e,"height",u+"px"),i.setStyle(e,"width",a+"px"),i.translate(this.textarea,Math.min(o,this.$size.scrollerWidth-a),Math.min(s,this.$size.height-u))},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.setMargin=function(e,t,n,r){var i=this.margin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,this.$updateCachedSize(!0,this.gutterWidth,this.$size.width,this.$size.height),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){this.$changes&&(e|=this.$changes,this.$changes=0);if(!this.session||!this.container.offsetWidth||this.$frozen||!e&&!t){this.$changes|=e;return}if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender"),this.session&&this.session.$bidiHandler&&this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){e|=this.$computeLayerConfig()|this.$loop.clear();if(n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig()|this.$loop.clear())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),i.translate(this.content,-this.scrollLeft,-n.offset);var s=n.width+2*this.$padding+"px",o=n.minHeight+"px";i.setStyle(this.content.style,"width",s),i.setStyle(this.content.style,"height",o)}e&this.CHANGE_H_SCROLL&&(i.translate(this.content,-this.scrollLeft,-n.offset),this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left");if(e&this.CHANGE_FULL){this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this._signal("afterRender");return}if(e&this.CHANGE_SCROLL){e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&(e&this.CHANGE_GUTTER||e&this.CHANGE_LINES?this.$gutterLayer.update(n):this.$gutterLayer.scrollLines(n)),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this._signal("afterRender");return}e&this.CHANGE_TEXT?(this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER?this.$showGutter&&this.$gutterLayer.update(n):e&this.CHANGE_CURSOR&&this.$highlightGutterLine&&this.$gutterLayer.updateLineHighlight(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal("afterRender")},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&n>this.$maxPixelHeight&&(n=this.$maxPixelHeight);var r=n<=2*this.lineHeight,i=!r&&e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||i!=this.$vScroll){i!=this.$vScroll&&(this.$vScroll=i,this.scrollBarV.setVisible(i));var s=this.container.clientWidth;this.container.style.height=n+"px",this.$updateCachedSize(!0,this.$gutterWidth,s,n),this.desiredHeight=n,this._signal("autosize")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,s=this.$getLongestLine(),o=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-s-2*this.$padding<0),u=this.$horizScroll!==o;u&&(this.$horizScroll=o,this.scrollBarH.setVisible(o));var a=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var f=t.scrollerHeight+this.lineHeight,l=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=l;var c=this.scrollMargin;this.session.setScrollTop(Math.max(-c.top,Math.min(this.scrollTop,i-t.scrollerHeight+c.bottom))),this.session.setScrollLeft(Math.max(-c.left,Math.min(this.scrollLeft,s+2*this.$padding-t.scrollerWidth+c.right)));var h=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+l<0||this.scrollTop>c.top),p=a!==h;p&&(this.$vScroll=h,this.scrollBarV.setVisible(h));var d=this.scrollTop%this.lineHeight,v=Math.ceil(f/this.lineHeight)-1,m=Math.max(0,Math.round((this.scrollTop-d)/this.lineHeight)),g=m+v,y,b,w=this.lineHeight;m=e.screenToDocumentRow(m,0);var E=e.getFoldLine(m);E&&(m=E.start.row),y=e.documentToScreenRow(m,0),b=e.getRowLength(m)*w,g=Math.min(e.screenToDocumentRow(g,0),e.getLength()-1),f=t.scrollerHeight+e.getRowLength(g)*w+b,d=this.scrollTop-y*w;var S=0;if(this.layerConfig.width!=s||u)S=this.CHANGE_H_SCROLL;if(u||p)S|=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),p&&(s=this.$getLongestLine());return this.layerConfig={width:s,padding:this.$padding,firstRow:m,firstRowScreen:y,lastRow:g,lineHeight:w,characterWidth:this.characterWidth,minHeight:f,maxHeight:i,offset:d,gutterOffset:w?Math.max(0,Math.ceil((d+t.height-t.scrollerHeight)/w)):0,height:this.$size.scrollerHeight},this.session.$bidiHandler&&this.session.$bidiHandler.setContentWidth(s-this.$padding),S},this.$updateLines=function(){if(!this.$changedLines)return;var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(tthis.$textLayer.MAX_LINE_LENGTH&&(e=this.$textLayer.MAX_LINE_LENGTH+30),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t,n){if(this.$size.scrollerHeight===0)return;var r=this.$cursorLayer.getPixelPosition(e),i=r.left,s=r.top,o=n&&n.top||0,u=n&&n.bottom||0,a=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop;a+o>s?(t&&a+o>s+this.lineHeight&&(s-=t*this.$size.scrollerHeight),s===0&&(s=-this.scrollMargin.top),this.session.setScrollTop(s)):a+this.$size.scrollerHeight-ui?(i=1-this.scrollMargin.top)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom)return!0;if(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left)return!0;if(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right)return!0},this.pixelToScreenCoordinates=function(e,t){var n;if(this.$hasCssTransforms){n={top:0,left:0};var r=this.$fontMetrics.transformCoordinates([e,t]);e=r[1]-this.gutterWidth-this.margin.left,t=r[0]}else n=this.scroller.getBoundingClientRect();var i=e+this.scrollLeft-n.left-this.$padding,s=i/this.characterWidth,o=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),u=this.$blockCursor?Math.floor(s):Math.round(s);return{row:o,column:u,side:s-u>0?1:-1,offsetX:i}},this.screenToTextCoordinates=function(e,t){var n;if(this.$hasCssTransforms){n={top:0,left:0};var r=this.$fontMetrics.transformCoordinates([e,t]);e=r[1]-this.gutterWidth-this.margin.left,t=r[0]}else n=this.scroller.getBoundingClientRect();var i=e+this.scrollLeft-n.left-this.$padding,s=i/this.characterWidth,o=this.$blockCursor?Math.floor(s):Math.round(s),u=Math.floor((t+this.scrollTop-n.top)/this.lineHeight);return this.session.screenToDocumentPosition(u,Math.max(o,0),i)},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+(this.session.$bidiHandler.isBidiRow(r.row,e)?this.session.$bidiHandler.getPosLeft(r.column):Math.round(r.column*this.characterWidth)),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition=e,e.cssText||(e.cssText=this.textarea.style.cssText,e.keepTextAreaAtCursor=this.$keepTextAreaAtCursor),e.useTextareaForIME=this.$useTextareaForIME,this.$useTextareaForIME?(this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor(),this.$cursorLayer.element.style.display="none"):e.markerId=this.session.addMarker(e.markerRange,"ace_composition_marker","text")},this.setCompositionText=function(e){var t=this.session.selection.cursor;this.addToken(e,"composition_placeholder",t.row,t.column),this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;this.$composition.markerId&&this.session.removeMarker(this.$composition.markerId),i.removeCssClass(this.textarea,"ace_composition"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null,this.$cursorLayer.element.style.display=""},this.addToken=function(e,t,n,r){var i=this.session;i.bgTokenizer.lines[n]=null;var s={type:t,value:e},o=i.getTokens(n);if(r==null)o.push(s);else{var u=0;for(var a=0;a50&&e.length>this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e})}}).call(f.prototype);var l=function(e,t,n){var r=null,i=!1,u=Object.create(s),a=[],l=new f({messageBuffer:a,terminate:function(){},postMessage:function(e){a.push(e);if(!r)return;i?setTimeout(c):c()}});l.setEmitSync=function(e){i=e};var c=function(){var e=a.shift();e.command?r[e.command].apply(r,e.args):e.event&&u._signal(e.event,e.data)};return u.postMessage=function(e){l.onMessage({data:e})},u.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},u.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},o.loadModule(["worker",t],function(e){r=new e[n](u);while(a.length)c()}),l};t.UIWorkerClient=l,t.WorkerClient=f,t.createWorker=a}),ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;this.updateAnchors(e),i&&(this.length+=n);if(i&&!this.session.$fromUndo)if(e.action==="insert")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.insertMergedLines(a,e.lines)}else if(e.action==="remove")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.remove(new r(a.row,a.column,a.row,a.column-n))}this.$updating=!1,this.updateMarkers()},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(this.$updating)return;var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)},this.onCursorChange=function(e){if(this.$updating||!this.session)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.removeEventListener("change",this.$onUpdate),this.session.selection.removeEventListener("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(this.$undoStackDepth===-1)return;var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n1&&!this.inMultiSelectMode&&(this._signal("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length&&this.$onRemoveRange(e)},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal("removeRange",{ranges:e}),this.rangeCount===0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var n=this.getRange(),r=this.isBackwards(),s=n.start.row,o=n.end.row;if(s==o){if(r)var u=n.end,a=n.start;else var u=n.start,a=n.end;this.addRange(i.fromPoints(a,a)),this.addRange(i.fromPoints(u,u));return}var f=[],l=this.getLineRange(s,!0);l.start.column=n.start.column,f.push(l);for(var c=s+1;c1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.cursor),s=this.session.documentToScreenPosition(this.anchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column0)g--;if(g>0){var y=0;while(r[y].isEmpty())y++}for(var b=g;b>=y;b--)r[b].isEmpty()&&r.splice(b,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.setDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit("changeSelection")},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;if(!t.multiSelectAction){var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}else t.multiSelectAction=="forEach"?r=n.forEachSelection(t,e.args):t.multiSelectAction=="forEachLine"?r=n.forEachSelection(t,e.args,!0):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});return r},this.forEachSelection=function(e,t,n){if(this.inVirtualSelectionMode)return;var r=n&&n.keepOrder,i=n==1||n&&n.$byLines,o=this.session,u=this.selection,a=u.rangeList,f=(r?u:a).ranges,l;if(!f.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var c=u._eventRegistry;u._eventRegistry={};var h=new s(o);this.inVirtualSelectionMode=!0;for(var p=f.length;p--;){if(i)while(p>0&&f[p].start.row==f[p-1].end.row)p--;h.fromOrientedRange(f[p]),h.index=p,this.selection=o.selection=h;var d=e.exec?e.exec(this,t||{}):e(this,t||{});!l&&d!==undefined&&(l=d),h.toOrientedRange(f[p])}h.detach(),this.selection=o.selection=u,this.inVirtualSelectionMode=!1,u._eventRegistry=c,u.mergeOverlappingRanges(),u.ranges[0]&&u.fromOrientedRange(u.ranges[0]);var v=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),v&&v.from==v.to&&this.renderer.animateScrolling(v.from),l},this.exitMultiSelectMode=function(){if(!this.inMultiSelectMode||this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e="";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var t=this.multiSelect.rangeList.ranges,n=[];for(var r=0;r0);u<0&&(u=0),f>=c&&(f=c-1)}var p=this.session.removeFullLines(u,f);p=this.$reAlignText(p,l),this.session.insert({row:u,column:0},p.join("\n")+"\n"),l||(o.start.column=0,o.end.column=p[p.length-1].length),this.selection.setRange(o)}else{s.forEach(function(e){t.substractPoint(e.cursor)});var d=0,v=Infinity,m=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>d&&(d=n.column),io?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=d,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e,t){function u(e){return a.stringRepeat(" ",e)}function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var n=!0,r=!0,i,s,o;return e.map(function(e){var t=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return t?i==null?(i=t[1].length,s=t[2].length,o=t[3].length,t):(i+s+o!=t[1].length+t[2].length+t[3].length&&(r=!1),i!=t[1].length&&(n=!1),i>t[1].length&&(i=t[1].length),st[3].length&&(o=t[3].length),t):[e]}).map(t?f:n?r?l:f:c)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off("addRange",this.$onAddRange),n.multiSelect.off("removeRange",this.$onRemoveRange),n.multiSelect.off("multiSelect",this.$onMultiSelect),n.multiSelect.off("singleSelect",this.$onSingleSelect),n.multiSelect.lead.off("change",this.$checkMultiselectChange),n.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m,e("./config").defineOptions(d.prototype,"editor",{enableMultiselect:{set:function(e){m(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++tf){var h=e.getLine(l).length;return new r(f,u,l,h)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=e.getFoldWidget(u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)}),ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}',t.$id="ace/theme/textmate";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),ace.define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./range").Range;(function(){this.getRowLength=function(e){var t;return this.lineWidgets?t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0:t=0,!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach();if(this.editor==e)return;this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets))},this.detach=function(e){var t=this.editor;if(!t)return;this.editor=null,t.widgetManager=null,t.renderer.off("beforeRender",this.measureWidgets),t.renderer.off("afterRender",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(!n||!e.action)return;var r=e.data,i=r.start.row,s=r.end.row,o=e.action=="add";for(var u=i+1;u0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var o=i;o<=s;o++){var u=r[o];if(!u||!u.el)continue;if(u.hidden){u.el.style.top=-100-(u.pixelHeight||0)+"px";continue}u._inDocument||(u._inDocument=!0,t.container.appendChild(u.el));var a=t.$cursorLayer.getPixelPosition({row:o,column:0},!0).top;u.coverLine||(a+=n.lineHeight*this.session.getRowLineCount(u.row)),u.el.style.top=a-n.offset+"px";var f=u.coverGutter?0:t.gutterWidth;u.fixedWidth||(f-=t.scrollLeft),u.el.style.left=f+"px",u.fullWidth&&u.screenWidth&&(u.el.style.minWidth=n.width+2*n.padding+"px"),u.fixedWidth?u.el.style.right=t.scrollBar.getWidth()+"px":u.el.style.right=""}}}).call(o.prototype),t.LineWidgets=o}),ace.define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[s]);if(o>0)r=s+1;else{if(!(o<0))return s;i=s-1}}return-(r+1)}function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.length)return;var i=o(r,{row:t,column:-1},s.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:i===0&&n<0&&(i=r.length-1);var u=r[i];if(!u||!n)return;if(u.row===t){do u=r[i+=n];while(u&&u.row===t);if(!u)return r.slice()}var a=[];t=u.row;do a[n<0?"unshift":"push"](u),u=r[i+=n];while(u&&u.row==t);return a.length&&a}var r=e("../line_widgets").LineWidgets,i=e("../lib/dom"),s=e("../range").Range;t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var s=e.getCursorPosition(),o=s.row,a=n.widgetManager.getWidgetsAtRow(o).filter(function(e){return e.type=="errorMarker"})[0];a?a.destroy():o-=t;var f=u(n,o,t),l;if(f){var c=f[0];s.column=(c.pos&&typeof c.column!="number"?c.pos.sc:c.column)||0,s.row=c.row,l=e.renderer.$gutterLayer.$annotations[s.row]}else{if(a)return;l={text:["Looks good!"],className:"ace_ok"}}e.session.unfold(s.row),e.selection.moveToPosition(s);var h={row:s.row,fixedWidth:!0,coverGutter:!0,el:i.createElement("div"),type:"errorMarker"},p=h.el.appendChild(i.createElement("div")),d=h.el.appendChild(i.createElement("div"));d.className="error_widget_arrow "+l.className;var v=e.renderer.$cursorLayer.getPixelPosition(s).left;d.style.left=v+e.renderer.gutterWidth-5+"px",h.el.className="error_widget_wrapper",p.className="error_widget "+l.className,p.innerHTML=l.text.join("
"),p.appendChild(i.createElement("div"));var m=function(e,t,n){if(t===0&&(n==="esc"||n==="return"))return h.destroy(),{command:"null"}};h.destroy=function(){if(e.$mouseHandler.isMousePressed)return;e.keyBinding.removeKeyboardHandler(m),n.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy)},e.keyBinding.addKeyboardHandler(m),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString(" .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }","")}),ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/range","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./range").Range,o=e("./editor").Editor,u=e("./edit_session").EditSession,a=e("./undomanager").UndoManager,f=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),t.config=e("./config"),t.require=e,typeof define=="function"&&(t.define=define),t.edit=function(e,n){if(typeof e=="string"){var s=e;e=document.getElementById(s);if(!e)throw new Error("ace.edit can't find div #"+s)}if(e&&e.env&&e.env.editor instanceof o)return e.env.editor;var u="";if(e&&/input|textarea/i.test(e.tagName)){var a=e;u=a.value,e=r.createElement("pre"),a.parentNode.replaceChild(e,a)}else e&&(u=e.textContent,e.innerHTML="");var l=t.createEditSession(u),c=new o(new f(e),l,n),h={document:l,editor:c,onResize:c.resize.bind(c,null)};return a&&(h.textarea=a),i.addListener(window,"resize",h.onResize),c.on("destroy",function(){i.removeListener(window,"resize",h.onResize),h.editor.container.env=null}),c.container.env=c.env=h,c},t.createEditSession=function(e,t){var n=new u(e,t);return n.setUndoManager(new a),n},t.Range=s,t.Editor=o,t.EditSession=u,t.UndoManager=a,t.VirtualRenderer=f,t.version="1.4.4"}); (function() { + ace.require(["ace/ace"], function(a) { + if (a) { + a.config.init(true); + a.define = ace.define; + } + if (!window.ace) + window.ace = a; + for (var key in a) if (a.hasOwnProperty(key)) + window.ace[key] = a[key]; + window.ace["default"] = window.ace; + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = window.ace; + } + }); + })(); diff --git a/docs/nightly/guide/en/async/index.html b/docs/nightly/guide/en/async/index.html new file mode 100644 index 000000000..f5987a40f --- /dev/null +++ b/docs/nightly/guide/en/async/index.html @@ -0,0 +1,223 @@ + + + + + + Async + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+ +
+ + + + + + + + +
+
+

Working with Async

+

Often, apps need to interact with file systems, network interfaces, hardware, or timers. This chapter provides an overview of using async code in Dioxus.

+

The Runtime

+

By default, Dioxus-Desktop ships with the Tokio runtime and automatically sets everything up for you. This is currently not configurable, though it would be easy to write an integration for Dioxus desktop that uses a different asynchronous runtime.

+

Dioxus is not currently thread-safe, so any async code you write does not need to be Send/Sync. That means that you can use non-thread-safe structures like Cell, Rc, and RefCell.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/async/spawn.html b/docs/nightly/guide/en/async/spawn.html new file mode 100644 index 000000000..0ce2ea479 --- /dev/null +++ b/docs/nightly/guide/en/async/spawn.html @@ -0,0 +1,277 @@ + + + + + + Spawning Futures + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Spawning Futures

+

The use_future and use_coroutine hooks are useful if you want to unconditionally spawn the future. Sometimes, though, you'll want to only spawn a future in response to an event, such as a mouse click. For example, suppose you need to send a request when the user clicks a "log in" button. For this, you can use cx.spawn:

+

+#![allow(unused)]
+fn main() {
+    let logged_in = use_state(cx, || false);
+
+    let log_in = move |_| {
+        cx.spawn({
+            let logged_in = logged_in.to_owned();
+
+            async move {
+                let resp = reqwest::Client::new()
+                    .post("http://example.com/login")
+                    .send()
+                    .await;
+
+                match resp {
+                    Ok(_data) => {
+                        println!("Login successful!");
+                        logged_in.set(true);
+                    }
+                    Err(_err) => {
+                        println!(
+                            "Login failed - you need a login server running on localhost:8080."
+                        )
+                    }
+                }
+            }
+        });
+    };
+
+    cx.render(rsx! {
+        button {
+            onclick: log_in,
+            "Login",
+        }
+    })
+}
+
+
+

Note: spawn will always spawn a new future. You most likely don't want to call it on every render.

+
+

Calling spawn will give you a JoinHandle which lets you cancel or pause the future.

+

Spawning Tokio Tasks

+

Sometimes, you might want to spawn a background task that needs multiple threads or talk to hardware that might block your app code. In these cases, we can directly spawn a Tokio task from our future. For Dioxus-Desktop, your task will be spawned onto Tokio's Multithreaded runtime:

+

+#![allow(unused)]
+fn main() {
+        cx.spawn(async {
+            let _ = tokio::spawn(async {}).await;
+
+            let _ = tokio::task::spawn_local(async {
+                // some !Send work
+            })
+            .await;
+        });
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/async/use_coroutine.html b/docs/nightly/guide/en/async/use_coroutine.html new file mode 100644 index 000000000..e9363c5d0 --- /dev/null +++ b/docs/nightly/guide/en/async/use_coroutine.html @@ -0,0 +1,421 @@ + + + + + + UseCoroutine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Coroutines

+

Another tool in your async toolbox are coroutines. Coroutines are futures that can be manually stopped, started, paused, and resumed.

+

Like regular futures, code in a coroutine will run until the next await point before yielding. This low-level control over asynchronous tasks is quite powerful, allowing for infinitely looping tasks like WebSocket polling, background timers, and other periodic actions.

+

use_coroutine

+

The use_coroutine hook allows you to create a coroutine. Most coroutines we write will be polling loops using async/await.

+

+#![allow(unused)]
+fn main() {
+fn app(cx: Scope) -> Element {
+    let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
+        // Connect to some sort of service
+        let mut conn = connect_to_ws_server().await;
+
+        // Wait for data on the service
+        while let Some(msg) = conn.next().await {
+            // handle messages
+        }
+    });
+}
+}
+
+

For many services, a simple async loop will handle the majority of use cases.

+

However, if we want to temporarily disable the coroutine, we can "pause" it using the pause method, and "resume" it using the resume method:

+

+#![allow(unused)]
+fn main() {
+let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
+    // code for syncing
+});
+
+if sync.is_running() {
+    cx.render(rsx!{
+        button {
+            onclick: move |_| sync.pause(),
+            "Disable syncing"
+        }
+    })
+} else {
+    cx.render(rsx!{
+        button {
+            onclick: move |_| sync.resume(),
+            "Enable syncing"
+        }
+    })
+}
+}
+
+

This pattern is where coroutines are extremely useful – instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.

+

Yielding Values

+

To yield values from a coroutine, simply bring in a UseState handle and set the value whenever your coroutine completes its work.

+

The future must be 'static – so any values captured by the task cannot carry any references to cx, such as a UseState.

+

You can use to_owned to create a clone of the hook handle which can be moved into the async closure.

+

+#![allow(unused)]
+fn main() {
+let sync_status = use_state(cx, || Status::Launching);
+let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
+    let sync_status = sync_status.to_owned();
+    async move {
+        loop {
+            delay_ms(1000).await;
+            sync_status.set(Status::Working);
+        }
+    }
+})
+}
+
+

To make this a bit less verbose, Dioxus exports the to_owned! macro which will create a binding as shown above, which can be quite helpful when dealing with many values.

+

+#![allow(unused)]
+fn main() {
+let sync_status = use_state(cx, || Status::Launching);
+let load_status = use_state(cx, || Status::Launching);
+let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
+    to_owned![sync_status, load_status];
+    async move {
+        // ...
+    }
+})
+}
+
+

Sending Values

+

You might've noticed the use_coroutine closure takes an argument called rx. What is that? Well, a common pattern in complex apps is to handle a bunch of async code at once. With libraries like Redux Toolkit, managing multiple promises at once can be challenging and a common source of bugs.

+

With Coroutines, we can centralize our async logic. The rx parameter is an Channel that allows code external to the coroutine to send data into the coroutine. Instead of looping on an external service, we can loop on the channel itself, processing messages from within our app without needing to spawn a new future. To send data into the coroutine, we would call "send" on the handle.

+

+#![allow(unused)]
+fn main() {
+use futures_util::stream::StreamExt;
+
+enum ProfileUpdate {
+    SetUsername(String),
+    SetAge(i32)
+}
+
+let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
+    let mut server = connect_to_server().await;
+
+    while let Ok(msg) = rx.next().await {
+        match msg {
+            ProfileUpdate::SetUsername(name) => server.update_username(name).await,
+            ProfileUpdate::SetAge(age) => server.update_age(age).await,
+        }
+    }
+});
+
+
+cx.render(rsx!{
+    button {
+        onclick: move |_| profile.send(ProfileUpdate::SetUsername("Bob".to_string())),
+        "Update username"
+    }
+})
+}
+
+
+

Note: In order to use/run the rx.next().await statement you will need to extend the [Stream] trait (used by [UnboundedReceiver]) by adding 'futures_util' as a dependency to your project and adding the use futures_util::stream::StreamExt;.

+
+

For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app.

+

+#![allow(unused)]
+fn main() {
+let profile = use_coroutine(cx, profile_service);
+let editor = use_coroutine(cx, editor_service);
+let sync = use_coroutine(cx, sync_service);
+
+async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
+    // do stuff
+}
+
+async fn sync_service(rx: UnboundedReceiver<SyncCommand>) {
+    // do stuff
+}
+
+async fn editor_service(rx: UnboundedReceiver<EditorCommand>) {
+    // do stuff
+}
+}
+
+

We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state within a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your actual state does not need to be tied up in a system like Fermi or Redux – the only Atoms that need to exist are those that are used to drive the display/UI.

+

+#![allow(unused)]
+fn main() {
+static USERNAME: Atom<String> = |_| "default".to_string();
+
+fn app(cx: Scope) -> Element {
+    let atoms = use_atom_root(cx);
+
+    use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
+
+    cx.render(rsx!{
+        Banner {}
+    })
+}
+
+fn Banner(cx: Scope) -> Element {
+    let username = use_read(cx, USERNAME);
+
+    cx.render(rsx!{
+        h1 { "Welcome back, {username}" }
+    })
+}
+}
+
+

Now, in our sync service, we can structure our state however we want. We only need to update the view values when ready.

+

+#![allow(unused)]
+fn main() {
+use futures_util::stream::StreamExt;
+
+enum SyncAction {
+    SetUsername(String),
+}
+
+async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
+    let username = atoms.write(USERNAME);
+    let errors = atoms.write(ERRORS);
+
+    while let Ok(msg) = rx.next().await {
+        match msg {
+            SyncAction::SetUsername(name) => {
+                if set_name_on_server(&name).await.is_ok() {
+                    username.set(name);
+                } else {
+                    errors.make_mut().push("SetUsernameFailed");
+                }
+            }
+        }
+    }
+}
+}
+
+

Automatic injection into the Context API

+

Coroutine handles are automatically injected through the context API. You can use the use_coroutine_handle hook with the message type as a generic to fetch a handle.

+

+#![allow(unused)]
+fn main() {
+fn Child(cx: Scope) -> Element {
+    let sync_task = use_coroutine_handle::<SyncAction>(cx);
+
+    sync_task.send(SyncAction::SetUsername);
+}
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/async/use_future.html b/docs/nightly/guide/en/async/use_future.html new file mode 100644 index 000000000..3acbb115f --- /dev/null +++ b/docs/nightly/guide/en/async/use_future.html @@ -0,0 +1,274 @@ + + + + + + UseFuture + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

UseFuture

+

use_future lets you run an async closure, and provides you with its result.

+

For example, we can make an API request (using reqwest) inside use_future:

+

+#![allow(unused)]
+fn main() {
+let future = use_future(cx, (), |_| async move {
+    reqwest::get("https://dog.ceo/api/breeds/image/random")
+        .await
+        .unwrap()
+        .json::<ApiResponse>()
+        .await
+});
+}
+
+

The code inside use_future will be submitted to the Dioxus scheduler once the component has rendered.

+

We can use .value() to get the result of the future. On the first run, since there's no data ready when the component loads, its value will be None. However, once the future is finished, the component will be re-rendered and the value will now be Some(...), containing the return value of the closure.

+

We can then render that result:

+

+#![allow(unused)]
+fn main() {
+cx.render(match future.value() {
+    Some(Ok(response)) => rsx! {
+        button {
+            onclick: move |_| future.restart(),
+            "Click to fetch another doggo"
+        }
+        div {
+            img {
+                max_width: "500px",
+                max_height: "500px",
+                src: "{response.image_url}",
+            }
+        }
+    },
+    Some(Err(_)) => rsx! { div { "Loading dogs failed" } },
+    None => rsx! { div { "Loading dogs..." } },
+})
+}
+
+

Restarting the Future

+

The UseFuture handle provides a restart method. It can be used to execute the future again, producing a new value.

+

Dependencies

+

Often, you will need to run the future again every time some value (e.g. a prop) changes. Rather than calling restart manually, you can provide a tuple of "dependencies" to the hook. It will automatically re-run the future when any of those dependencies change. Example:

+

+#![allow(unused)]
+fn main() {
+let future = use_future(cx, (breed,), |(breed,)| async move {
+    reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
+        .await
+        .unwrap()
+        .json::<ApiResponse>()
+        .await
+});
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/ayu-highlight.css b/docs/nightly/guide/en/ayu-highlight.css new file mode 100644 index 000000000..0c45c6f14 --- /dev/null +++ b/docs/nightly/guide/en/ayu-highlight.css @@ -0,0 +1,79 @@ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ + +.hljs { + display: block; + overflow-x: auto; + background: #191f26; + color: #e6e1cf; + padding: 0.5em; +} + +.hljs-comment, +.hljs-quote { + color: #5c6773; + font-style: italic; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-attr, +.hljs-regexp, +.hljs-link, +.hljs-selector-id, +.hljs-selector-class { + color: #ff7733; +} + +.hljs-number, +.hljs-meta, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ffee99; +} + +.hljs-string, +.hljs-bullet { + color: #b8cc52; +} + +.hljs-title, +.hljs-built_in, +.hljs-section { + color: #ffb454; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-symbol { + color: #ff7733; +} + +.hljs-name { + color: #36a3d9; +} + +.hljs-tag { + color: #00568d; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #91b362; +} + +.hljs-deletion { + color: #d96c75; +} diff --git a/docs/nightly/guide/en/best_practices/antipatterns.html b/docs/nightly/guide/en/best_practices/antipatterns.html new file mode 100644 index 000000000..509d123fd --- /dev/null +++ b/docs/nightly/guide/en/best_practices/antipatterns.html @@ -0,0 +1,288 @@ + + + + + + Antipatterns + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Antipatterns

+

This example shows what not to do and provides a reason why a given pattern is considered an "AntiPattern". Most anti-patterns are considered wrong for performance or code re-usability reasons.

+

Unnecessarily Nested Fragments

+

Fragments don't mount a physical element to the DOM immediately, so Dioxus must recurse into its children to find a physical DOM node. This process is called "normalization". This means that deeply nested fragments make Dioxus perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true DOM element.

+

Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing an API for registering shared state without the Context Provider pattern.

+

+#![allow(unused)]
+fn main() {
+    // ❌ Don't unnecessarily nest fragments
+    let _ = cx.render(rsx!(
+        Fragment {
+            Fragment {
+                Fragment {
+                    Fragment {
+                        Fragment {
+                            div { "Finally have a real node!" }
+                        }
+                    }
+                }
+            }
+        }
+    ));
+
+    // ✅ Render shallow structures
+    cx.render(rsx!(
+        div { "Finally have a real node!" }
+    ))
+}
+
+

Incorrect Iterator Keys

+

As described in the dynamic rendering chapter, list items must have unique keys that are associated with the same items across renders. This helps Dioxus associate state with the contained components and ensures good diffing performance. Do not omit keys, unless you know that the list will never change.

+

+#![allow(unused)]
+fn main() {
+    let data: &HashMap<_, _> = &cx.props.data;
+
+    // ❌ No keys
+    cx.render(rsx! {
+        ul {
+            data.values().map(|value| rsx!(
+                li { "List item: {value}" }
+            ))
+        }
+    });
+
+    // ❌ Using index as keys
+    cx.render(rsx! {
+        ul {
+            cx.props.data.values().enumerate().map(|(index, value)| rsx!(
+                li { key: "{index}", "List item: {value}" }
+            ))
+        }
+    });
+
+    // ✅ Using unique IDs as keys:
+    cx.render(rsx! {
+        ul {
+            cx.props.data.iter().map(|(key, value)| rsx!(
+                li { key: "{key}", "List item: {value}" }
+            ))
+        }
+    })
+}
+
+

Avoid Interior Mutability in Props

+

While it is technically acceptable to have a Mutex or a RwLock in the props, they will be difficult to use.

+

Suppose you have a struct User containing the field username: String. If you pass a Mutex<User> prop to a UserComponent component, that component may wish to pass the username as a &str prop to a child component. However, it cannot pass that borrowed field down, since it only would live as long as the Mutex's lock, which belongs to the UserComponent function. Therefore, the component will be forced to clone the username field.

+

Avoid Updating State During Render

+

Every time you update the state, Dioxus needs to re-render the component – this is inefficient! Consider refactoring your code to avoid this.

+

Also, if you unconditionally update the state during render, it will be re-rendered in an infinite loop.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/best_practices/error_handling.html b/docs/nightly/guide/en/best_practices/error_handling.html new file mode 100644 index 000000000..96a26b2cb --- /dev/null +++ b/docs/nightly/guide/en/best_practices/error_handling.html @@ -0,0 +1,367 @@ + + + + + + Error Handling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Error handling

+

A selling point of Rust for web development is the reliability of always knowing where errors can occur and being forced to handle them

+

However, we haven't talked about error handling at all in this guide! In this chapter, we'll cover some strategies in handling errors to ensure your app never crashes.

+

The simplest – returning None

+

Astute observers might have noticed that Element is actually a type alias for Option<VNode>. You don't need to know what a VNode is, but it's important to recognize that we could actually return nothing at all:

+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    None
+}
+}
+
+

This lets us add in some syntactic sugar for operations we think shouldn't fail, but we're still not confident enough to "unwrap" on.

+
+

The nature of Option<VNode> might change in the future as the try trait gets upgraded.

+
+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    // immediately return "None"
+    let name = cx.use_hook(|_| Some("hi"))?;
+}
+}
+
+

Early return on result

+

Because Rust can't accept both Options and Results with the existing try infrastructure, you'll need to manually handle Results. This can be done by converting them into Options or by explicitly handling them.

+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    // Convert Result to Option
+    let name = cx.use_hook(|_| "1.234").parse().ok()?;
+
+
+    // Early return
+    let count = cx.use_hook(|_| "1.234");
+    let val = match count.parse() {
+        Ok(val) => val
+        Err(err) => return cx.render(rsx!{ "Parsing failed" })
+    };
+}
+}
+
+

Notice that while hooks in Dioxus do not like being called in conditionals or loops, they are okay with early returns. Returning an error state early is a completely valid way of handling errors.

+

Match results

+

The next "best" way of handling errors in Dioxus is to match on the error locally. This is the most robust way of handling errors, though it doesn't scale to architectures beyond a single component.

+

To do this, we simply have an error state built into our component:

+

+#![allow(unused)]
+fn main() {
+let err = use_state(cx, || None);
+}
+
+

Whenever we perform an action that generates an error, we'll set that error state. We can then match on the error in a number of ways (early return, return Element, etc).

+

+#![allow(unused)]
+fn main() {
+fn Commandline(cx: Scope) -> Element {
+    let error = use_state(cx, || None);
+
+    cx.render(match *error {
+        Some(error) => rsx!(
+            h1 { "An error occured" }
+        )
+        None => rsx!(
+            input {
+                oninput: move |_| error.set(Some("bad thing happened!")),
+            }
+        )
+    })
+}
+}
+
+

Passing error states through components

+

If you're dealing with a handful of components with minimal nesting, you can just pass the error handle into child components.

+

+#![allow(unused)]
+fn main() {
+fn Commandline(cx: Scope) -> Element {
+    let error = use_state(cx, || None);
+
+    if let Some(error) = **error {
+        return cx.render(rsx!{ "An error occured" });
+    }
+
+    cx.render(rsx!{
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+    })
+}
+}
+
+

Much like before, our child components can manually set the error during their own actions. The advantage to this pattern is that we can easily isolate error states to a few components at a time, making our app more predictable and robust.

+

Going global

+

A strategy for handling cascaded errors in larger apps is through signaling an error using global state. This particular pattern involves creating an "error" context, and then setting it wherever relevant. This particular method is not as "sophisticated" as React's error boundary, but it is more fitting for Rust.

+

To get started, consider using a built-in hook like use_context and use_context_provider or Fermi. Of course, it's pretty easy to roll your own hook too.

+

At the "top" of our architecture, we're going to want to explicitly declare a value that could be an error.

+

+#![allow(unused)]
+fn main() {
+enum InputError {
+    None,
+    TooLong,
+    TooShort,
+}
+
+static INPUT_ERROR: Atom<InputError> = |_| InputError::None;
+}
+
+

Then, in our top level component, we want to explicitly handle the possible error state for this part of the tree.

+

+#![allow(unused)]
+fn main() {
+fn TopLevel(cx: Scope) -> Element {
+    let error = use_read(cx, INPUT_ERROR);
+
+    match error {
+        TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
+        TooShort => return cx.render(rsx!{ "FAILED: Too Short!" }),
+        _ => {}
+    }
+}
+}
+
+

Now, whenever a downstream component has an error in its actions, it can simply just set its own error state:

+

+#![allow(unused)]
+fn main() {
+fn Commandline(cx: Scope) -> Element {
+    let set_error = use_set(cx, INPUT_ERROR);
+
+    cx.render(rsx!{
+        input {
+            oninput: move |evt| {
+                if evt.value.len() > 20 {
+                    set_error(InputError::TooLong);
+                }
+            }
+        }
+    })
+}
+}
+
+

This approach to error handling is best in apps that have "well defined" error states. Consider using a crate like thiserror or anyhow to simplify the generation of the error types.

+

This pattern is widely popular in many contexts and is particularly helpful whenever your code generates a non-recoverable error. You can gracefully capture these "global" error states without panicking or mucking up state.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/best_practices/index.html b/docs/nightly/guide/en/best_practices/index.html new file mode 100644 index 000000000..007cdc283 --- /dev/null +++ b/docs/nightly/guide/en/best_practices/index.html @@ -0,0 +1,228 @@ + + + + + + Best Practices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Best Practices

+

Reusable Components

+

As much as possible, break your code down into small, reusable components and hooks, instead of implementing large chunks of the UI in a single component. This will help you keep the code maintainable – it is much easier to e.g. add, remove or re-order parts of the UI if it is organized in components.

+

Organize your components in modules to keep the codebase easy to navigate!

+

Minimize State Dependencies

+

While it is possible to share state between components, this should only be done when necessary. Any component that is associated with a particular state object needs to be re-rendered when that state changes. For this reason:

+
    +
  • Keep state local to a component if possible
  • +
  • When sharing state through props, only pass down the specific data necessary
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/book.js b/docs/nightly/guide/en/book.js new file mode 100644 index 000000000..aa153a3e1 --- /dev/null +++ b/docs/nightly/guide/en/book.js @@ -0,0 +1,762 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +// Global variable, shared between modules +function playground_text(playground) { + let code_block = playground.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else { + return code_block.textContent; + } +} + +(function codeSnippets() { + function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playgrounds = Array.from(document.querySelectorAll(".playground")); + if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playground_block, playground_crates); + }); + // add Ctrl-Enter command to execute rust code + editor.commands.addCommand({ + name: "run", + bindKey: { + win: "Ctrl-Enter", + mac: "Ctrl-Enter" + }, + exec: _editor => run_rust_code(playground_block) + }); + } + } + } + + // updates the visibility of play button based on `no_run` class and + // used crates vs ones available on http://play.rust-lang.org + function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } + } + + function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if(classes.contains("edition2018")) { + edition = "2018"; + } else if(classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + let code_nodes = Array + .from(document.querySelectorAll('code')) + // Don't highlight `inline code` blocks in headers. + .filter(function (node) {return !node.parentElement.classList.contains("header"); }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + code_nodes + .filter(function (node) {return node.classList.contains("editable"); }) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + Array + code_nodes + .filter(function (node) {return !node.classList.contains("editable"); }) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + code_nodes.forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) { + + var lines = Array.from(block.querySelectorAll('.boring')); + // If no lines were hidden, return + if (!lines.length) { return; } + block.classList.add("hide-boring"); + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + var pre_block = block.parentNode; + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-eye')) { + e.target.classList.remove('fa-eye'); + e.target.classList.add('fa-eye-slash'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.remove('hide-boring'); + } else if (e.target.classList.contains('fa-eye-slash')) { + e.target.classList.remove('fa-eye-slash'); + e.target.classList.add('fa-eye'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.add('hide-boring'); + } + }); + }); + + if (window.playground_copyable) { + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playground')) { + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var clipButton = document.createElement('button'); + clipButton.className = 'fa fa-copy clip-button'; + clipButton.title = 'Copy to clipboard'; + clipButton.setAttribute('aria-label', clipButton.title); + clipButton.innerHTML = ''; + + buttons.insertBefore(clipButton, buttons.firstChild); + } + }); + } + + // Process playground code blocks + Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'fa fa-play play-button'; + runCodeButton.hidden = true; + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + if (window.playground_copyable) { + var copyCodeClipboardButton = document.createElement('button'); + copyCodeClipboardButton.className = 'fa fa-copy clip-button'; + copyCodeClipboardButton.innerHTML = ''; + copyCodeClipboardButton.title = 'Copy to clipboard'; + copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); + + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + } + + let code_block = pre_block.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + var undoChangesButton = document.createElement('button'); + undoChangesButton.className = 'fa fa-history reset-button'; + undoChangesButton.title = 'Undo changes'; + undoChangesButton.setAttribute('aria-label', undoChangesButton.title); + + buttons.insertBefore(undoChangesButton, buttons.firstChild); + + undoChangesButton.addEventListener('click', function () { + let editor = window.ace.edit(code_block); + editor.setValue(editor.originalCode); + editor.clearSelection(); + }); + } + }); +})(); + +(function themes() { + var html = document.querySelector('html'); + var themeToggleButton = document.getElementById('theme-toggle'); + var themePopup = document.getElementById('theme-list'); + var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); + var stylesheets = { + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), + }; + + function showThemes() { + themePopup.style.display = 'block'; + themeToggleButton.setAttribute('aria-expanded', true); + themePopup.querySelector("button#" + get_theme()).focus(); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function get_theme() { + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (theme === null || theme === undefined) { + return default_theme; + } else { + return theme; + } + } + + function set_theme(theme, store = true) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = false; + stylesheets.highlight.disabled = true; + + ace_theme = "ace/theme/tomorrow_night"; + } else if (theme == 'ayu') { + stylesheets.ayuHighlight.disabled = false; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = true; + ace_theme = "ace/theme/tomorrow_night"; + } else { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = false; + ace_theme = "ace/theme/dawn"; + } + + setTimeout(function () { + themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor; + }, 1); + + if (window.ace && window.editors) { + window.editors.forEach(function (editor) { + editor.setTheme(ace_theme); + }); + } + + var previousTheme = get_theme(); + + if (store) { + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + } + + html.classList.remove(previousTheme); + html.classList.add(theme); + } + + // Set theme + var theme = get_theme(); + + set_theme(theme, false); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else if (e.target.parentElement.className === "theme") { + theme = e.target.parentElement.id; + } else { + return; + } + set_theme(theme); + }); + + themePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { + hideThemes(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { + hideThemes(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!themePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideThemes(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + themePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + themePopup.querySelector('li:last-child button').focus(); + break; + } + }); +})(); + +(function languages() { + var languageToggleButton = document.getElementById('language-toggle'); + var languagePopup = document.getElementById('language-list'); + + if (languageToggleButton !== null) { + function showLanguages() { + languagePopup.style.display = 'block'; + languageToggleButton.setAttribute('aria-expanded', true); + } + + function hideLanguages() { + languagePopup.style.display = 'none'; + languageToggleButton.setAttribute('aria-expanded', false); + languageToggleButton.focus(); + } + + function set_language(language) { + console.log("Set language " + language) + } + + languageToggleButton.addEventListener('click', function () { + if (languagePopup.style.display === 'block') { + hideLanguages(); + } else { + showLanguages(); + } + }); + + languagePopup.addEventListener('click', function (e) { + var language = e.target.id || e.target.parentElement.id; + set_language(language); + }); + + languagePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !languageToggleButton.contains(e.relatedTarget) && !languagePopup.contains(e.relatedTarget)) { + hideLanguages(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (languagePopup.style.display === 'block' && !languageToggleButton.contains(e.target) && !languagePopup.contains(e.target)) { + hideLanguages(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!languagePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideLanguages(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + languagePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + languagePopup.querySelector('li:last-child button').focus(); + break; + } + }); + } +})(); + +(function sidebar() { + var html = document.querySelector("html"); + var sidebar = document.getElementById("sidebar"); + var sidebarLinks = document.querySelectorAll('#sidebar a'); + var sidebarToggleButton = document.getElementById("sidebar-toggle"); + var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); + var firstContact = null; + + function showSidebar() { + html.classList.remove('sidebar-hidden') + html.classList.add('sidebar-visible'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', 0); + }); + sidebarToggleButton.setAttribute('aria-expanded', true); + sidebar.setAttribute('aria-hidden', false); + try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } + } + + + var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle'); + + function toggleSection(ev) { + ev.currentTarget.parentElement.classList.toggle('expanded'); + } + + Array.from(sidebarAnchorToggles).forEach(function (el) { + el.addEventListener('click', toggleSection); + }); + + function hideSidebar() { + html.classList.remove('sidebar-visible') + html.classList.add('sidebar-hidden'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', -1); + }); + sidebarToggleButton.setAttribute('aria-expanded', false); + sidebar.setAttribute('aria-hidden', true); + try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } + } + + // Toggle sidebar + sidebarToggleButton.addEventListener('click', function sidebarToggle() { + if (html.classList.contains("sidebar-hidden")) { + var current_width = parseInt( + document.documentElement.style.getPropertyValue('--sidebar-width'), 10); + if (current_width < 150) { + document.documentElement.style.setProperty('--sidebar-width', '150px'); + } + showSidebar(); + } else if (html.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + sidebarResizeHandle.addEventListener('mousedown', initResize, false); + + function initResize(e) { + window.addEventListener('mousemove', resize, false); + window.addEventListener('mouseup', stopResize, false); + html.classList.add('sidebar-resizing'); + } + function resize(e) { + var pos = (e.clientX - sidebar.offsetLeft); + if (pos < 20) { + hideSidebar(); + } else { + if (html.classList.contains("sidebar-hidden")) { + showSidebar(); + } + pos = Math.min(pos, window.innerWidth - 100); + document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); + } + } + //on mouseup remove windows functions mousemove & mouseup + function stopResize(e) { + html.classList.remove('sidebar-resizing'); + window.removeEventListener('mousemove', resize, false); + window.removeEventListener('mouseup', stopResize, false); + } + + document.addEventListener('touchstart', function (e) { + firstContact = { + x: e.touches[0].clientX, + time: Date.now() + }; + }, { passive: true }); + + document.addEventListener('touchmove', function (e) { + if (!firstContact) + return; + + var curX = e.touches[0].clientX; + var xDiff = curX - firstContact.x, + tDiff = Date.now() - firstContact.time; + + if (tDiff < 250 && Math.abs(xDiff) >= 150) { + if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) + showSidebar(); + else if (xDiff < 0 && curX < 300) + hideSidebar(); + + firstContact = null; + } + }, { passive: true }); + + // Scroll sidebar to current active section + var activeSection = document.getElementById("sidebar").querySelector(".active"); + if (activeSection) { + // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView + activeSection.scrollIntoView({ block: 'center' }); + } +})(); + +(function chapterNavigation() { + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (window.search && window.search.hasFocus()) { return; } + + switch (e.key) { + case 'ArrowRight': + e.preventDefault(); + var nextButton = document.querySelector('.nav-chapters.next'); + if (nextButton) { + window.location.href = nextButton.href; + } + break; + case 'ArrowLeft': + e.preventDefault(); + var previousButton = document.querySelector('.nav-chapters.previous'); + if (previousButton) { + window.location.href = previousButton.href; + } + break; + } + }); +})(); + +(function clipboard() { + var clipButtons = document.querySelectorAll('.clip-button'); + + function hideTooltip(elem) { + elem.firstChild.innerText = ""; + elem.className = 'fa fa-copy clip-button'; + } + + function showTooltip(elem, msg) { + elem.firstChild.innerText = msg; + elem.className = 'fa fa-copy tooltipped'; + } + + var clipboardSnippets = new ClipboardJS('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playground = trigger.closest("pre"); + return playground_text(playground); + } + }); + + Array.from(clipButtons).forEach(function (clipButton) { + clipButton.addEventListener('mouseout', function (e) { + hideTooltip(e.currentTarget); + }); + }); + + clipboardSnippets.on('success', function (e) { + e.clearSelection(); + showTooltip(e.trigger, "Copied!"); + }); + + clipboardSnippets.on('error', function (e) { + showTooltip(e.trigger, "Clipboard error!"); + }); +})(); + +(function scrollToTop () { + var menuTitle = document.querySelector('.menu-title'); + + menuTitle.addEventListener('click', function () { + document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); + }); +})(); + +(function controllMenu() { + var menu = document.getElementById('menu-bar'); + + (function controllPosition() { + var scrollTop = document.scrollingElement.scrollTop; + var prevScrollTop = scrollTop; + var minMenuY = -menu.clientHeight - 50; + // When the script loads, the page can be at any scroll (e.g. if you reforesh it). + menu.style.top = scrollTop + 'px'; + // Same as parseInt(menu.style.top.slice(0, -2), but faster + var topCache = menu.style.top.slice(0, -2); + menu.classList.remove('sticky'); + var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster + document.addEventListener('scroll', function () { + scrollTop = Math.max(document.scrollingElement.scrollTop, 0); + // `null` means that it doesn't need to be updated + var nextSticky = null; + var nextTop = null; + var scrollDown = scrollTop > prevScrollTop; + var menuPosAbsoluteY = topCache - scrollTop; + if (scrollDown) { + nextSticky = false; + if (menuPosAbsoluteY > 0) { + nextTop = prevScrollTop; + } + } else { + if (menuPosAbsoluteY > 0) { + nextSticky = true; + } else if (menuPosAbsoluteY < minMenuY) { + nextTop = prevScrollTop + minMenuY; + } + } + if (nextSticky === true && stickyCache === false) { + menu.classList.add('sticky'); + stickyCache = true; + } else if (nextSticky === false && stickyCache === true) { + menu.classList.remove('sticky'); + stickyCache = false; + } + if (nextTop !== null) { + menu.style.top = nextTop + 'px'; + topCache = nextTop; + } + prevScrollTop = scrollTop; + }, { passive: true }); + })(); + (function controllBorder() { + menu.classList.remove('bordered'); + document.addEventListener('scroll', function () { + if (menu.offsetTop === 0) { + menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); + } + }, { passive: true }); + })(); +})(); diff --git a/docs/nightly/guide/en/clipboard.min.js b/docs/nightly/guide/en/clipboard.min.js new file mode 100644 index 000000000..02c549e35 --- /dev/null +++ b/docs/nightly/guide/en/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.4 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n + + + + + Guiding Principles + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Overall Goals

+

This document outlines some of the overall goals for Dioxus. These goals are not set in stone, but they represent general guidelines for the project.

+

The goal of Dioxus is to make it easy to build cross-platform applications that scale.

+

Cross-Platform

+

Dioxus is designed to be cross-platform by default. This means that it should be easy to build applications that run on the web, desktop, and mobile. However, Dioxus should also be flexible enough to allow users to opt into platform-specific features when needed. The use_eval is one example of this. By default, Dioxus does not assume that the platform supports JavaScript, but it does provide a hook that allows users to opt into JavaScript when needed.

+

Performance

+

As Dioxus applications grow, they should remain relatively performant without the need for manual optimizations. There will be cases where manual optimizations are needed, but Dioxus should try to make these cases as rare as possible.

+

One of the benefits of the core architecture of Dioxus is that it delivers reasonable performance even when components are rerendered often. It is based on a Virtual Dom which performs diffing which should prevent unnecessary re-renders even when large parts of the component tree are rerun. On top of this, Dioxus groups static parts of the RSX tree together to skip diffing them entirely.

+

Type Safety

+

As teams grow, the Type safety of Rust is a huge advantage. Dioxus should leverage this advantage to make it easy to build applications with large teams.

+

To take full advantage of Rust's type system, Dioxus should try to avoid exposing public Any types and string-ly typed APIs where possible.

+

Developer Experience

+

Dioxus should be easy to learn and ergonomic to use.

+
    +
  • +

    The API of Dioxus attempts to remain close to React's API where possible. This makes it easier for people to learn Dioxus if they already know React

    +
  • +
  • +

    We can avoid the tradeoff between simplicity and flexibility by providing multiple layers of API: One for the very common use case, one for low-level control

    +
      +
    • Hooks: the hooks crate has the most common use cases, but cx.hook provides a way to access the underlying persistent reference if needed.
    • +
    • The builder pattern in platform Configs: The builder pattern is used to default to the most common use case, but users can change the defaults if needed.
    • +
    +
  • +
  • +

    Documentation:

    +
      +
    • All public APIs should have rust documentation
    • +
    • Examples should be provided for all public features. These examples both serve as documentation and testing. They are checked by CI to ensure that they continue to compile
    • +
    • The most common workflows should be documented in the guide
    • +
    +
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/contributing/index.html b/docs/nightly/guide/en/contributing/index.html new file mode 100644 index 000000000..081c82653 --- /dev/null +++ b/docs/nightly/guide/en/contributing/index.html @@ -0,0 +1,255 @@ + + + + + + Contributing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Contributing

+

Development happens in the Dioxus GitHub repository. If you've found a bug or have an idea for a feature, please submit an issue (but first check if someone hasn't done it already).

+

GitHub discussions can be used as a place to ask for help or talk about features. You can also join our Discord channel where some development discussion happens.

+

Improving Docs

+

If you'd like to improve the docs, PRs are welcome! Both Rust docs (source) and this guide (source) can be found in the GitHub repo.

+

Working on the Ecosystem

+

Part of what makes React great is the rich ecosystem. We'd like the same for Dioxus! So if you have a library in mind that you'd like to write and many people would benefit from, it will be appreciated. You can browse npm.js for inspiration. Once you are done, add your library to the awesome dioxus list or share it in the #I-made-a-thing channel on Discord.

+

Bugs & Features

+

If you've fixed an open issue, feel free to submit a PR! You can also take a look at the roadmap and work on something in there. Consider reaching out to the team first to make sure everyone's on the same page, and you don't do useless work!

+

All pull requests (including those made by a team member) must be approved by at least one other team member. +Larger, more nuanced decisions about design, architecture, breaking changes, trade-offs, etc. are made by team consensus.

+

Tools

+

The following tools can be helpful when developing Dioxus. Many of these tools are used in the CI pipeline. Running them locally before submitting a PR instead of waiting for CI can save time.

+ +
cargo fmt --all
+
+
    +
  • All code is formatted with rustfmt
  • +
+
cargo check --workspace --examples --tests
+
+
    +
  • All code is linted with Clippy
  • +
+
cargo clippy --workspace --examples --tests -- -D warnings
+
+
    +
  • Crates that use unsafe are checked for undefined behavior with MIRI. MIRI can be helpful to debug what unsafe code is causing issues. Only code that does not interact with system calls can be checked with MIRI. Currently, this is used for the two MIRI tests in dioxus-core and dioxus-native-core.
  • +
+
cargo miri test --package dioxus-core --test miri_stress
+cargo miri test --package dioxus-native-core --test miri_native
+
+
    +
  • Rust analyzer can be very helpful for quick feedback in your IDE.
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/contributing/project_structure.html b/docs/nightly/guide/en/contributing/project_structure.html new file mode 100644 index 000000000..fb9c4cd39 --- /dev/null +++ b/docs/nightly/guide/en/contributing/project_structure.html @@ -0,0 +1,273 @@ + + + + + + Project Structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Project Struture

+

There are many packages in the Dioxus organization. This document will help you understand the purpose of each package and how they fit together.

+

Renderers

+
    +
  • Desktop: A Render that Runs Dioxus applications natively, but renders them with the system webview
  • +
  • Mobile: A Render that Runs Dioxus applications natively, but renders them with the system webview. This is currently a copy of the desktop render
  • +
  • Web: Renders Dioxus applications in the browser by compiling to WASM and manipulating the DOM
  • +
  • Liveview: A Render that Runs on the server, and renders using a websocket proxy in the browser
  • +
  • Rink: A Renderer that renders a HTML-like tree into a terminal
  • +
  • TUI: A Renderer that uses Rink to render a Dioxus application in a terminal
  • +
  • Blitz-Core: An experimental native renderer that renders a HTML-like tree using WGPU.
  • +
  • Blitz: An experimental native renderer that uses Blitz-Core to render a Dioxus application using WGPU.
  • +
  • SSR: A Render that Runs Dioxus applications on the server, and renders them to HTML
  • +
+

State Management/Hooks

+
    +
  • Hooks: A collection of common hooks for Dioxus applications
  • +
  • Signals: A experimental state management library for Dioxus applications. This currently contains a Copy version of UseRef
  • +
  • Dioxus STD: A collection of platform agnostic hooks to interact with system interfaces (The clipboard, camera, etc.).
  • +
  • Fermi: A global state management library for Dioxus applications. +Router: A client-side router for Dioxus applications
  • +
+

Core utilities

+
    +
  • core: The core virtual dom implementation every Dioxus application uses + +
  • +
  • RSX: The core parsing for RSX used for hot reloading, autoformatting, and the macro
  • +
  • core-macro: The rsx! macro used to write Dioxus applications. (This is a wrapper over the RSX crate)
  • +
  • HTML macro: A html-like alternative to the RSX macro
  • +
+

Native Renderer Utilities

+ +

Web renderer tooling

+
    +
  • HTML: defines html specific elements, events, and attributes
  • +
  • Interpreter: defines browser bindings used by the web and desktop renderers
  • +
+

Developer tooling

+
    +
  • hot-reload: Macro that uses the RSX crate to hot reload static parts of any rsx! macro. This macro works with any non-web renderer with an integration
  • +
  • autofmt: Formats RSX code
  • +
  • rsx-rosetta: Handles conversion between HTML and RSX
  • +
  • CLI: A Command Line Interface and VSCode extension to assist with Dioxus usage
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/contributing/roadmap.html b/docs/nightly/guide/en/contributing/roadmap.html new file mode 100644 index 000000000..9fe99cfc7 --- /dev/null +++ b/docs/nightly/guide/en/contributing/roadmap.html @@ -0,0 +1,380 @@ + + + + + + Roadmap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Roadmap & Feature-set

+

This feature set and roadmap can help you decide if what Dioxus can do today works for you.

+

If a feature that you need doesn't exist or you want to contribute to projects on the roadmap, feel free to get involved by joining the discord.

+

Generally, here's the status of each platform:

+
    +
  • +

    Web: Dioxus is a great choice for pure web-apps – especially for CRUD/complex apps. However, it does lack the ecosystem of React, so you might be missing a component library or some useful hook.

    +
  • +
  • +

    SSR: Dioxus is a great choice for pre-rendering, hydration, and rendering HTML on a web endpoint. Be warned – the VirtualDom is not (currently) Send + Sync.

    +
  • +
  • +

    Desktop: You can build very competent single-window desktop apps right now. However, multi-window apps require support from Dioxus core and are not ready.

    +
  • +
  • +

    Mobile: Mobile support is very young. You'll be figuring things out as you go and there are not many support crates for peripherals.

    +
  • +
  • +

    LiveView: LiveView support is very young. You'll be figuring things out as you go. Thankfully, none of it is too hard and any work can be upstreamed into Dioxus.

    +
  • +
+

Features

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStatusDescription
Conditional Rendering✅if/then to hide/show component
Map, Iterator✅map/filter/reduce to produce rsx!
Keyed Components✅advanced diffing with keys
Web✅renderer for web browser
Desktop (webview)✅renderer for desktop
Shared State (Context)✅share state through the tree
Hooks✅memory cells in components
SSR✅render directly to string
Component Children✅cx.children() as a list of nodes
Headless components✅components that don't return real elements
Fragments✅multiple elements without a real root
Manual Props✅Manually pass in props with spread syntax
Controlled Inputs✅stateful wrappers around inputs
CSS/Inline Styles✅syntax for inline styles/attribute groups
Custom elements✅Define new element primitives
Suspense✅schedule future render from future/promise
Integrated error handling✅Gracefully handle errors with ? syntax
NodeRef✅gain direct access to nodes
Re-hydration✅Pre-render to HTML to speed up first contentful paint
Jank-Free Rendering✅Large diffs are segmented across frames for silky-smooth transitions
Effects✅Run effects after a component has been committed to render
Portals🛠Render nodes outside of the traditional tree structure
Cooperative Scheduling🛠Prioritize important events over non-important events
Server Components🛠Hybrid components for SPA and Server
Bundle Splitting👀Efficiently and asynchronously load the app
Lazy Components👀Dynamically load the new components as the page is loaded
1st class global state✅redux/recoil/mobx on top of context
Runs natively✅runs as a portable binary w/o a runtime (Node)
Subtree Memoization✅skip diffing static element subtrees
High-efficiency templates✅rsx! calls are translated to templates on the DOM's side
Compile-time correct✅Throw errors on invalid template layouts
Heuristic Engine✅track component memory usage to minimize future allocations
Fine-grained reactivity👀Skip diffing for fine-grain updates
+
    +
  • ✅ = implemented and working
  • +
  • 🛠 = actively being worked on
  • +
  • 👀 = not yet implemented or being worked on
  • +
+

Roadmap

+

These Features are planned for the future of Dioxus:

+

Core

+
    +
  • +Release of Dioxus Core
  • +
  • +Upgrade documentation to include more theory and be more comprehensive
  • +
  • +Support for HTML-side templates for lightning-fast dom manipulation
  • +
  • +Support for multiple renderers for same virtualdom (subtrees)
  • +
  • +Support for ThreadSafe (Send + Sync)
  • +
  • +Support for Portals
  • +
+

SSR

+
    +
  • +SSR Support + Hydration
  • +
  • +Integrated suspense support for SSR
  • +
+

Desktop

+
    +
  • +Declarative window management
  • +
  • +Templates for building/bundling
  • +
  • +Access to Canvas/WebGL context natively
  • +
+

Mobile

+
    +
  • +Mobile standard library +
      +
    • +GPS
    • +
    • +Camera
    • +
    • +filesystem
    • +
    • +Biometrics
    • +
    • +WiFi
    • +
    • +Bluetooth
    • +
    • +Notifications
    • +
    • +Clipboard
    • +
    +
  • +
  • +Animations
  • +
+

Bundling (CLI)

+
    +
  • +Translation from HTML into RSX
  • +
  • +Dev server
  • +
  • +Live reload
  • +
  • +Translation from JSX into RSX
  • +
  • +Hot module replacement
  • +
  • +Code splitting
  • +
  • +Asset macros
  • +
  • +Css pipeline
  • +
  • +Image pipeline
  • +
+

Essential hooks

+
    +
  • +Router
  • +
  • +Global state management
  • +
  • +Resize observer
  • +
+

Work in Progress

+

Build Tool

+

We are currently working on our own build tool called Dioxus CLI which will support:

+
    +
  • an interactive TUI
  • +
  • on-the-fly reconfiguration
  • +
  • hot CSS reloading
  • +
  • two-way data binding between browser and source code
  • +
  • an interpreter for rsx!
  • +
  • ability to publish to github/netlify/vercel
  • +
  • bundling for iOS/Desktop/etc
  • +
+

Server Component Support

+

While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between Wasm and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA.

+

Native rendering

+

We are currently working on a native renderer for Dioxus using WGPU called Blitz. This will allow you to build apps that are rendered natively for iOS, Android, and Desktop.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/contributing/walkthrough_readme.html b/docs/nightly/guide/en/contributing/walkthrough_readme.html new file mode 100644 index 000000000..09bc4afae --- /dev/null +++ b/docs/nightly/guide/en/contributing/walkthrough_readme.html @@ -0,0 +1,433 @@ + + + + + + Walkthrough of Internals + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Walkthrough of the Hello World Example Internals

+

This walkthrough will take you through the internals of the Hello World example program. It will explain how major parts of Dioxus internals interact with each other to take the readme example from a source file to a running application. This guide should serve as a high-level overview of the internals of Dioxus. It is not meant to be a comprehensive guide.

+

The Source File

+

We start will a hello world program. This program renders a desktop app with the text "Hello World" in a webview.

+
//! Example: README.md showcase
+//!
+//! The example from the README.md.
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus_desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let mut count = use_state(cx, || 0);
+
+    cx.render(rsx! {
+        h1 { "High-Five counter: {count}" }
+        button { onclick: move |_| count += 1, "Up high!" }
+        button { onclick: move |_| count -= 1, "Down low!" }
+    })
+}
+
+

+

The rsx! Macro

+

Before the Rust compiler runs the program, it will expand all macros. Here is what the hello world example looks like expanded:

+
use dioxus::prelude::*;
+
+fn main() {
+    dioxus_desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let mut count = use_state(cx, || 0);
+
+    cx.render(
+        // rsx expands to LazyNodes::new
+        ::dioxus::core::LazyNodes::new(
+            move |__cx: &::dioxus::core::ScopeState| -> ::dioxus::core::VNode {
+                // The template is every static part of the rsx
+                static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
+                    // This is the source location of the rsx that generated this template. This is used to make hot rsx reloading work. Hot rsx reloading just replaces the template with a new one generated from the rsx by the CLI.
+                    name: "examples\\readme.rs:14:15:250",
+                    // The root nodes are the top level nodes of the rsx
+                    roots: &[
+                        // The h1 node
+                        ::dioxus::core::TemplateNode::Element {
+                            // Find the built in h1 tag in the dioxus_elements crate exported by the dioxus html crate
+                            tag: dioxus_elements::h1::TAG_NAME,
+                            namespace: dioxus_elements::h1::NAME_SPACE,
+                            attrs: &[],
+                            // The children of the h1 node
+                            children: &[
+                                // The dynamic count text node
+                                // Any nodes that are dynamic have a dynamic placeholder with a unique index
+                                ::dioxus::core::TemplateNode::DynamicText {
+                                    // This index is used to find what element in `dynamic_nodes` to use instead of the placeholder
+                                    id: 0usize,
+                                },
+                            ],
+                        },
+                        // The up high button node
+                        ::dioxus::core::TemplateNode::Element {
+                            tag: dioxus_elements::button::TAG_NAME,
+                            namespace: dioxus_elements::button::NAME_SPACE,
+                            attrs: &[
+                                // The dynamic onclick listener attribute
+                                // Any attributes that are dynamic have a dynamic placeholder with a unique index.
+                                ::dioxus::core::TemplateAttribute::Dynamic {
+                                    // Similar to dynamic nodes, dynamic attributes have a unique index used to find the attribute in `dynamic_attrs` to use instead of the placeholder
+                                    id: 0usize,
+                                },
+                            ],
+                            children: &[::dioxus::core::TemplateNode::Text { text: "Up high!" }],
+                        },
+                        // The down low button node
+                        ::dioxus::core::TemplateNode::Element {
+                            tag: dioxus_elements::button::TAG_NAME,
+                            namespace: dioxus_elements::button::NAME_SPACE,
+                            attrs: &[
+                                // The dynamic onclick listener attribute
+                                ::dioxus::core::TemplateAttribute::Dynamic { id: 1usize },
+                            ],
+                            children: &[::dioxus::core::TemplateNode::Text { text: "Down low!" }],
+                        },
+                    ],
+                    // Node paths is a list of paths to every dynamic node in the rsx
+                    node_paths: &[
+                        // The first node path is the path to the dynamic node with an id of 0 (the count text node)
+                        &[
+                            // Go to the index 0 root node
+                            0u8,
+                            //
+                            // Go to the first child of the root node
+                            0u8,
+                        ],
+                    ],
+                    // Attr paths is a list of paths to every dynamic attribute in the rsx
+                    attr_paths: &[
+                        // The first attr path is the path to the dynamic attribute with an id of 0 (the up high button onclick listener)
+                        &[
+                            // Go to the index 1 root node
+                            1u8,
+                        ],
+                        // The second attr path is the path to the dynamic attribute with an id of 1 (the down low button onclick listener)
+                        &[
+                            // Go to the index 2 root node
+                            2u8,
+                        ],
+                    ],
+                };
+                // The VNode is a reference to the template with the dynamic parts of the rsx
+                ::dioxus::core::VNode {
+                    parent: None,
+                    key: None,
+                    // The static template this node will use. The template is stored in a Cell so it can be replaced with a new template when hot rsx reloading is enabled
+                    template: std::cell::Cell::new(TEMPLATE),
+                    root_ids: Default::default(),
+                    dynamic_nodes: __cx.bump().alloc([
+                        // The dynamic count text node (dynamic node id 0)
+                        __cx.text_node(format_args!("High-Five counter: {0}", count)),
+                    ]),
+                    dynamic_attrs: __cx.bump().alloc([
+                        // The dynamic up high button onclick listener (dynamic attribute id 0)
+                        dioxus_elements::events::onclick(__cx, move |_| count += 1),
+                        // The dynamic down low button onclick listener (dynamic attribute id 1)
+                        dioxus_elements::events::onclick(__cx, move |_| count -= 1),
+                    ]),
+                }
+            },
+        ),
+    )
+}
+
+

The rsx macro separates the static parts of the rsx (the template) and the dynamic parts (the dynamic_nodes and dynamic_attributes).

+

The static template only contains the parts of the rsx that cannot change at runtime with holes for the dynamic parts:

+

+

The dynamic_nodes and dynamic_attributes are the parts of the rsx that can change at runtime:

+

+

Launching the App

+

The app is launched by calling the launch function with the root component. Internally, this function will create a new web view using wry and create a virtual dom with the root component. This guide will not explain the renderer in-depth, but you can read more about it in the custom renderer section.

+

The Virtual DOM

+

Before we dive into the initial render in the virtual dom, we need to discuss what the virtual dom is. The virtual dom is a representation of the dom that is used to diff the current dom from the new dom. This diff is then used to create a list of mutations that need to be applied to the dom.

+

The Virtual Dom roughly looks like this:

+

+#![allow(unused)]
+fn main() {
+pub struct VirtualDom {
+    // All the templates that have been created or set durring hot reloading
+    pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>,
+
+    // A slab of all the scopes that have been created
+    pub(crate) scopes: ScopeSlab,
+
+    // All scopes that have been marked as dirty
+    pub(crate) dirty_scopes: BTreeSet<DirtyScope>,
+
+    // Every element is actually a dual reference - one to the template and the other to the dynamic node in that template
+    pub(crate) elements: Slab<ElementRef>,
+
+    // This receiver is used to receive messages from hooks about what scopes need to be marked as dirty
+    pub(crate) rx: futures_channel::mpsc::UnboundedReceiver<SchedulerMsg>,
+
+    // The changes queued up to be sent to the renderer
+    pub(crate) mutations: Mutations<'static>,
+}
+}
+
+
+

What is a slab? +A slab acts like a hashmap with integer keys if you don't care about the value of the keys. It is internally backed by a dense vector which makes it more efficient than a hashmap. When you insert a value into a slab, it returns an integer key that you can use to retrieve the value later.

+
+
+

How does Dioxus use slabs? +Dioxus uses "synchronized slabs" to communicate between the renderer and the VDOM. When an node is created in the Virtual Dom, a ElementId is passed along with the mutation to the renderer to identify the node. These ids are used by the Virtual Dom to reference that nodes in future mutations like setting an attribute on a node or removing a node. +When the renderer sends an event to the Virtual Dom, it sends the ElementId of the node that the event was triggered on. The Virtual Dom uses this id to find the node in the slab and then run the necessary event handlers.

+
+

The virtual dom is a tree of scopes. A new scope is created for every component when it is first rendered and recycled when the component is unmounted.

+

Scopes serve three main purposes:

+
    +
  1. They store the state of hooks used by the component
  2. +
  3. They store the state for the context API
  4. +
  5. They store the current and previous VNode that was rendered for diffing
  6. +
+

The Initial Render

+

The root scope is created and rebuilt:

+
    +
  1. The root component is run
  2. +
  3. The root component returns a VNode
  4. +
  5. Mutations for the VNode are created and added to the mutation list (this may involve creating new child components)
  6. +
  7. The VNode is stored in the root scope
  8. +
+

After the root scope is built, the mutations are sent to the renderer to be applied to the dom.

+

After the initial render, the root scope looks like this:

+

+

Waiting for Events

+

The Virtual Dom will only ever rerender a scope if it is marked as dirty. Each hook is responsible for marking the scope as dirty if the state has changed. Hooks can mark a scope as dirty by sending a message to the Virtual Dom's channel.

+

There are generally two ways a scope is marked as dirty:

+
    +
  1. The renderer triggers an event: This causes an event listener to be called if needed which may mark a component as dirty
  2. +
  3. The renderer calls wait for work: This polls futures which may mark a component as dirty
  4. +
+

Once at least one scope is marked as dirty, the renderer can call render_with_deadline to diff the dirty scopes.

+

Diffing Scopes

+

If the user clicked the "up high" button, the root scope would be marked as dirty by the use_state hook. Once the desktop renderer calls render_with_deadline, the root scope would be diffed.

+

To start the diffing process, the component is run. After the root component is run it will look like this:

+

+

Next, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.

+

When a component is re-rendered, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.

+

The diffing algorithm goes through the list of dynamic attributes and nodes and compares them to the previous VNode. If the attribute or node has changed, a mutation that describes the change is added to the mutation list.

+

Here is what the diffing algorithm looks like for the root scope (red lines indicate that a mutation was generated, and green lines indicate that no mutation was generated)

+

+

Conclusion

+

This is only a brief overview of how the Virtual Dom works. There are several aspects not yet covered in this guide including how the Virtual Dom handles async-components, keyed diffing, and how it uses bump allocation to efficiently allocate VNodes. If need more information about the Virtual Dom, you can read the code of the core crate or reach out to us on Discord.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/css/chrome.css b/docs/nightly/guide/en/css/chrome.css new file mode 100644 index 000000000..0ed18a02f --- /dev/null +++ b/docs/nightly/guide/en/css/chrome.css @@ -0,0 +1,542 @@ +/* CSS for UI elements (a.k.a. chrome) */ + +@import 'variables.css'; + +::-webkit-scrollbar { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +#searchresults a, +.content a:link, +a:visited, +a > .hljs { + color: var(--links); +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-bottom-color: var(--bg); + border-bottom-width: 1px; + border-bottom-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-bottom-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: 150px; + min-width: 90px; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-top: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +.previous { + float: left; +} + +.next { + float: right; + right: var(--page-padding); +} + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +@media only screen and (max-width: 1380px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 5px; + top: 5px; + + color: var(--sidebar-fg); + cursor: pointer; +} +pre > .buttons :hover { + color: var(--sidebar-active); +} +pre > .buttons i { + margin-left: 8px; +} +pre > .buttons button { + color: inherit; + background: transparent; + border: none; + cursor: inherit; +} +pre > .result { + margin-top: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding: 0 3px 1px 3px; + margin: 0 -3px -1px -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin: 5px auto 0px auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding: 18px 0 0 5px; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); + border-bottom: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-left: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin: 5px 0 0 20px; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 0.875em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +.sidebar-hidden .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +.sidebar-visible .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +@media only screen and (min-width: 620px) { + .sidebar-visible .page-wrapper { + transform: none; + margin-left: var(--sidebar-width); + } +} + +.chapter { + list-style: none outside none; + padding-left: 0; + line-height: 2.2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-left: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-top: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-left: 20px; + line-height: 1.9em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; +} +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 10px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} +.theme-popup .theme:hover:first-child, +.theme-popup .theme:hover:last-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} + +/* Language Menu Popup */ + +.language-popup { + position: absolute; + left: 150px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; +} +.language-popup .default { + color: var(--icons); +} +.language-popup .language { + width: 100%; + border: 0; + margin: 0; + padding: 2px 10px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.language-popup .language:hover { + background-color: var(--theme-hover); +} +.language-popup .language:hover:first-child, +.language-popup .language:hover:last-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} + +.language-popup a { + color: var(--fg); + text-decoration: none; +} diff --git a/docs/nightly/guide/en/css/general.css b/docs/nightly/guide/en/css/general.css new file mode 100644 index 000000000..ef2ba5048 --- /dev/null +++ b/docs/nightly/guide/en/css/general.css @@ -0,0 +1,182 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 62.5%; +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.6rem; + overflow-x: hidden; +} + +code { + font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important; + font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */ +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-top: 2.5em; } +h4, h5 { margin-top: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 15px; + padding-bottom: 50px; +} +.content main { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: .1em solid var(--quote-border); + border-bottom: .1em solid var(--quote-border); +} + + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/docs/nightly/guide/en/css/print.css b/docs/nightly/guide/en/css/print.css new file mode 100644 index 000000000..5e690f755 --- /dev/null +++ b/docs/nightly/guide/en/css/print.css @@ -0,0 +1,54 @@ + +#sidebar, +#menu-bar, +.nav-chapters, +.mobile-nav-chapters { + display: none; +} + +#page-wrapper.page-wrapper { + transform: none; + margin-left: 0px; + overflow-y: initial; +} + +#content { + max-width: none; + margin: 0; + padding: 0; +} + +.page { + overflow-y: initial; +} + +code { + background-color: #666666; + border-radius: 5px; + + /* Force background to be printed in Chrome */ + -webkit-print-color-adjust: exact; +} + +pre > .buttons { + z-index: 2; +} + +a, a:visited, a:active, a:hover { + color: #4183c4; + text-decoration: none; +} + +h1, h2, h3, h4, h5, h6 { + page-break-inside: avoid; + page-break-after: avoid; +} + +pre, code { + page-break-inside: avoid; + white-space: pre-wrap; +} + +.fa { + display: none !important; +} diff --git a/docs/nightly/guide/en/css/variables.css b/docs/nightly/guide/en/css/variables.css new file mode 100644 index 000000000..56b634bc3 --- /dev/null +++ b/docs/nightly/guide/en/css/variables.css @@ -0,0 +1,253 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 15px; + --content-max-width: 750px; + --menu-bar-height: 50px; +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #20609f; + + --inline-code-color: #301900; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/docs/nightly/guide/en/custom_renderer/index.html b/docs/nightly/guide/en/custom_renderer/index.html new file mode 100644 index 000000000..3005b0003 --- /dev/null +++ b/docs/nightly/guide/en/custom_renderer/index.html @@ -0,0 +1,823 @@ + + + + + + Custom Renderer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Custom Renderer

+

Dioxus is an incredibly portable framework for UI development. The lessons, knowledge, hooks, and components you acquire over time can always be used for future projects. However, sometimes those projects cannot leverage a supported renderer or you need to implement your own better renderer.

+

Great news: the design of the renderer is entirely up to you! We provide suggestions and inspiration with the 1st party renderers, but only really require processing Mutations and sending UserEvents.

+

The specifics:

+

Implementing the renderer is fairly straightforward. The renderer needs to:

+
    +
  1. Handle the stream of edits generated by updates to the virtual DOM
  2. +
  3. Register listeners and pass events into the virtual DOM's event system
  4. +
+

Essentially, your renderer needs to process edits and generate events to update the VirtualDOM. From there, you'll have everything needed to render the VirtualDOM to the screen.

+

Internally, Dioxus handles the tree relationship, diffing, memory management, and the event system, leaving as little as possible required for renderers to implement themselves.

+

For reference, check out the javascript interpreter or tui renderer as a starting point for your custom renderer.

+

Templates

+

Dioxus is built around the concept of Templates. Templates describe a UI tree known at compile time with dynamic parts filled at runtime. This is useful internally to make skip diffing static nodes, but it is also useful for the renderer to reuse parts of the UI tree. This can be useful for things like a list of items. Each item could contain some static parts and some dynamic parts. The renderer can use the template to create a static part of the UI once, clone it for each element in the list, and then fill in the dynamic parts.

+

Mutations

+

The Mutation type is a serialized enum that represents an operation that should be applied to update the UI. The variants roughly follow this set:

+

+#![allow(unused)]
+fn main() {
+enum Mutation {
+    AppendChildren,
+    AssignId,
+    CreatePlaceholder,
+    CreateTextNode,
+    HydrateText,
+    LoadTemplate,
+    ReplaceWith,
+    ReplacePlaceholder,
+    InsertAfter,
+    InsertBefore,
+    SetAttribute,
+    SetText,
+    NewEventListener,
+    RemoveEventListener,
+    Remove,
+    PushRoot,
+}
+}
+
+

The Dioxus diffing mechanism operates as a stack machine where the LoadTemplate, CreatePlaceholder, and CreateTextNode mutations pushes a new "real" DOM node onto the stack and AppendChildren, InsertAfter, InsertBefore, ReplacePlaceholder, and ReplaceWith all remove nodes from the stack.

+

Node storage

+

Dioxus saves and loads elements with IDs. Inside the VirtualDOM, this is just tracked as as a u64.

+

Whenever a CreateElement edit is generated during diffing, Dioxus increments its node counter and assigns that new element its current NodeCount. The RealDom is responsible for remembering this ID and pushing the correct node when id is used in a mutation. Dioxus reclaims the IDs of elements when removed. To stay in sync with Dioxus you can use a sparse Vec (Vec<Option>) with possibly unoccupied items. You can use the ids as indexes into the Vec for elements, and grow the Vec when an id does not exist.

+

An Example

+

For the sake of understanding, let's consider this example – a very simple UI declaration:

+

+#![allow(unused)]
+fn main() {
+rsx!( h1 {"count: {x}"} )
+}
+
+

Building Templates

+

The above rsx will create a template that contains one static h1 tag and a placeholder for a dynamic text node. The template contains the static parts of the UI, and ids for the dynamic parts along with the paths to access them.

+

The template will look something like this:

+

+#![allow(unused)]
+fn main() {
+Template {
+    // Some id that is unique for the entire project
+    name: "main.rs:1:1:0",
+    // The root nodes of the template
+    roots: &[
+        TemplateNode::Element {
+            tag: "h1",
+            namespace: None,
+            attrs: &[],
+            children: &[
+                TemplateNode::DynamicText {
+                    id: 0
+                },
+            ],
+        }
+    ],
+    // the path to each of the dynamic nodes
+    node_paths: &[
+        // the path to dynamic node with a id of 0
+        &[
+            // on the first root node
+            0,
+            // the first child of the root node
+            0,
+        ]
+    ],
+    // the path to each of the dynamic attributes
+    attr_paths: &'a [&'a [u8]],
+}
+}
+
+
+

For more detailed docs about the struture of templates see the Template api docs

+
+

This template will be sent to the renderer in the list of templates supplied with the mutations the first time it is used. Any time the renderer encounters a LoadTemplate mutation after this, it should clone the template and store it in the given id.

+

For dynamic nodes and dynamic text nodes, a placeholder node should be created and inserted into the UI so that the node can be modified later.

+

In HTML renderers, this template could look like this:

+
<h1>""</h1>
+
+

Applying Mutations

+

After the renderer has created all of the new templates, it can begin to process the mutations.

+

When the renderer starts, it should contain the Root node on the stack and store the Root node with an id of 0. The Root node is the top-level node of the UI. In HTML, this is the <div id="main"> element.

+

+#![allow(unused)]
+fn main() {
+instructions: []
+stack: [
+    RootNode,
+]
+nodes: [
+    RootNode,
+]
+}
+
+

The first mutation is a LoadTemplate mutation. This tells the renderer to load a root from the template with the given id. The renderer will then push the root node of the template onto the stack and store it with an id for later. In this case, the root node is an h1 element.

+

+#![allow(unused)]
+fn main() {
+instructions: [
+    LoadTemplate {
+        // the id of the template
+        name: "main.rs:1:1:0",
+        // the index of the root node in the template
+        index: 0,
+        // the id to store
+        id: ElementId(1),
+    }
+]
+stack: [
+    RootNode,
+    <h1>""</h1>,
+]
+nodes: [
+    RootNode,
+    <h1>""</h1>,
+]
+}
+
+

Next, Dioxus will create the dynamic text node. The diff algorithm decides that this node needs to be created, so Dioxus will generate the Mutation HydrateText. When the renderer receives this instruction, it will navigate to the placeholder text node in the template and replace it with the new text.

+

+#![allow(unused)]
+fn main() {
+instructions: [
+    LoadTemplate {
+        name: "main.rs:1:1:0",
+        index: 0,
+        id: ElementId(1),
+    },
+    HydrateText {
+        // the id to store the text node
+        id: ElementId(2),
+        // the text to set
+        text: "count: 0",
+    }
+]
+stack: [
+    RootNode,
+    <h1>"count: 0"</h1>,
+]
+nodes: [
+    RootNode,
+    <h1>"count: 0"</h1>,
+    "count: 0",
+]
+}
+
+

Remember, the h1 node is not attached to anything (it is unmounted) so Dioxus needs to generate an Edit that connects the h1 node to the Root. It depends on the situation, but in this case, we use AppendChildren. This pops the text node off the stack, leaving the Root element as the next element on the stack.

+

+#![allow(unused)]
+fn main() {
+instructions: [
+    LoadTemplate {
+        name: "main.rs:1:1:0",
+        index: 0,
+        id: ElementId(1),
+    },
+    HydrateText {
+        id: ElementId(2),
+        text: "count: 0",
+    },
+    AppendChildren {
+        // the id of the parent node
+        id: ElementId(0),
+        // the number of nodes to pop off the stack and append
+        m: 1
+    }
+]
+stack: [
+    RootNode,
+]
+nodes: [
+    RootNode,
+    <h1>"count: 0"</h1>,
+    "count: 0",
+]
+}
+
+

Over time, our stack looked like this:

+

+#![allow(unused)]
+fn main() {
+[Root]
+[Root, <h1>""</h1>]
+[Root, <h1>"count: 0"</h1>]
+[Root]
+}
+
+

Conveniently, this approach completely separates the Virtual DOM and the Real DOM. Additionally, these edits are serializable, meaning we can even manage UIs across a network connection. This little stack machine and serialized edits make Dioxus independent of platform specifics.

+

Dioxus is also really fast. Because Dioxus splits the diff and patch phase, it's able to make all the edits to the RealDOM in a very short amount of time (less than a single frame) making rendering very snappy. It also allows Dioxus to cancel large diffing operations if higher priority work comes in while it's diffing.

+

This little demo serves to show exactly how a Renderer would need to process a mutation stream to build UIs.

+

Event loop

+

Like most GUIs, Dioxus relies on an event loop to progress the VirtualDOM. The VirtualDOM itself can produce events as well, so it's important for your custom renderer can handle those too.

+

The code for the WebSys implementation is straightforward, so we'll add it here to demonstrate how simple an event loop is:

+
pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
+    // Push the body element onto the WebsysDom's stack machine
+    let mut websys_dom = crate::new::WebsysDom::new(prepare_websys_dom());
+    websys_dom.stack.push(root_node);
+
+    // Rebuild or hydrate the virtualdom
+    let mutations = self.internal_dom.rebuild();
+    websys_dom.apply_mutations(mutations);
+
+    // Wait for updates from the real dom and progress the virtual dom
+    loop {
+        let user_input_future = websys_dom.wait_for_event();
+        let internal_event_future = self.internal_dom.wait_for_work();
+
+        match select(user_input_future, internal_event_future).await {
+            Either::Left((_, _)) => {
+                let mutations = self.internal_dom.work_with_deadline(|| false);
+                websys_dom.apply_mutations(mutations);
+            },
+            Either::Right((event, _)) => websys_dom.handle_event(event),
+        }
+
+        // render
+    }
+}
+
+

It's important to decode what the real events are for your event system into Dioxus' synthetic event system (synthetic meaning abstracted). This simply means matching your event type and creating a Dioxus UserEvent type. Right now, the virtual event system is modeled almost entirely around the HTML spec, but we are interested in slimming it down.

+
fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
+    match event.type_().as_str() {
+        "keydown" => {
+            let event: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
+            UserEvent::KeyboardEvent(UserEvent {
+                scope_id: None,
+                priority: EventPriority::Medium,
+                name: "keydown",
+                // This should be whatever element is focused
+                element: Some(ElementId(0)),
+                data: Arc::new(KeyboardData{
+                    char_code: event.char_code(),
+                    key: event.key(),
+                    key_code: event.key_code(),
+                    alt_key: event.alt_key(),
+                    ctrl_key: event.ctrl_key(),
+                    meta_key: event.meta_key(),
+                    shift_key: event.shift_key(),
+                    location: event.location(),
+                    repeat: event.repeat(),
+                    which: event.which(),
+                })
+            })
+        }
+        _ => todo!()
+    }
+}
+
+

Custom raw elements

+

If you need to go as far as relying on custom elements/attributes for your renderer – you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away. You can drop in your elements any time you want, with little hassle. However, you must be sure your renderer can handle the new namespace.

+

For more examples and information on how to create custom namespaces, see the dioxus_html crate.

+

Native Core

+

If you are creating a renderer in rust, the native-core crate provides some utilities to implement a renderer. It provides an abstraction over Mutations and Templates and contains helpers that can handle the layout and text editing for you.

+

The RealDom

+

The RealDom is a higher-level abstraction over updating the Dom. It uses an entity component system to manage the state of nodes. This system allows you to modify insert and modify arbitrary components on nodes. On top of this, the RealDom provides a way to manage a tree of nodes, and the State trait provides a way to automatically add and update these components when the tree is modified. It also provides a way to apply Mutations to the RealDom.

+

Example

+

Let's build a toy renderer with borders, size, and text color. +Before we start let's take a look at an example element we can render:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!{
+    div{
+        color: "red",
+        p{
+            border: "1px solid black",
+            "hello world"
+        }
+    }
+})
+}
+
+

In this tree, the color depends on the parent's color. The layout depends on the children's layout, the current text, and the text size. The border depends on only the current node.

+

In the following diagram arrows represent dataflow:

+

+

To help in building a Dom, native-core provides the State trait and a RealDom struct. The State trait provides a way to describe how states in a node depend on other states in its relatives. By describing how to update a single node from its relations, native-core will derive a way to update the states of all nodes for you. Once you have a state you can provide it as a generic to RealDom. RealDom provides all of the methods to interact and update your new dom.

+

Native Core cannot create all of the required methods for the State trait, but it can derive some of them. To implement the State trait, you must implement the following methods and let the #[partial_derive_state] macro handle the rest:

+
// All states must derive Component (https://docs.rs/shipyard/latest/shipyard/derive.Component.html)
+// They also must implement Default or provide a custom implementation of create in the State trait
+#[derive(Default, Component)]
+struct MyState;
+
+/// Derive some of the boilerplate for the State implementation
+#[partial_derive_state]
+impl State for MyState {
+    // The states of the parent nodes this state depends on
+    type ParentDependencies = ();
+
+    // The states of the child nodes this state depends on
+    type ChildDependencies = (Self,);
+
+    // The states of the current node this state depends on
+    type NodeDependencies = ();
+
+    // The parts of the current text, element, or placeholder node in the tree that this state depends on
+    const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new();
+
+    // How to update the state of the current node based on the state of the parent nodes, child nodes, and the current node
+    // Returns true if the node was updated and false if the node was not updated
+    fn update<'a>(
+        &mut self,
+        // The view of the current node limited to the parts this state depends on
+        _node_view: NodeView<()>,
+        // The state of the current node that this state depends on
+        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        // The state of the parent nodes that this state depends on
+        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        // The state of the child nodes that this state depends on
+        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
+        // The context of the current node used to pass global state into the tree
+        _context: &SendAnyMap,
+    ) -> bool {
+        todo!()
+    }
+
+    // partial_derive_state will generate a default implementation of all the other methods
+}
+
+

Lets take a look at how to implement the State trait for a simple renderer.

+

+#![allow(unused)]
+fn main() {
+struct FontSize(f64);
+
+// All states need to derive Component
+#[derive(Default, Debug, Copy, Clone, Component)]
+struct Size(f64, f64);
+
+/// Derive some of the boilerplate for the State implementation
+#[partial_derive_state]
+impl State for Size {
+    type ParentDependencies = ();
+
+    // The size of the current node depends on the size of its children
+    type ChildDependencies = (Self,);
+
+    type NodeDependencies = ();
+
+    // Size only cares about the width, height, and text parts of the current node
+    const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
+        // Get access to the width and height attributes
+        .with_attrs(AttributeMaskBuilder::Some(&["width", "height"]))
+        // Get access to the text of the node
+        .with_text();
+
+    fn update<'a>(
+        &mut self,
+        node_view: NodeView<()>,
+        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
+        context: &SendAnyMap,
+    ) -> bool {
+        let font_size = context.get::<FontSize>().unwrap().0;
+        let mut width;
+        let mut height;
+        if let Some(text) = node_view.text() {
+            // if the node has text, use the text to size our object
+            width = text.len() as f64 * font_size;
+            height = font_size;
+        } else {
+            // otherwise, the size is the maximum size of the children
+            width = children
+                .iter()
+                .map(|(item,)| item.0)
+                .reduce(|accum, item| if accum >= item { accum } else { item })
+                .unwrap_or(0.0);
+
+            height = children
+                .iter()
+                .map(|(item,)| item.1)
+                .reduce(|accum, item| if accum >= item { accum } else { item })
+                .unwrap_or(0.0);
+        }
+        // if the node contains a width or height attribute it overrides the other size
+        for a in node_view.attributes().into_iter().flatten() {
+            match &*a.attribute.name {
+                "width" => width = a.value.as_float().unwrap(),
+                "height" => height = a.value.as_float().unwrap(),
+                // because Size only depends on the width and height, no other attributes will be passed to the member
+                _ => panic!(),
+            }
+        }
+        // to determine what other parts of the dom need to be updated we return a boolean that marks if this member changed
+        let changed = (width != self.0) || (height != self.1);
+        *self = Self(width, height);
+        changed
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Default, Component)]
+struct TextColor {
+    r: u8,
+    g: u8,
+    b: u8,
+}
+
+#[partial_derive_state]
+impl State for TextColor {
+    // TextColor depends on the TextColor part of the parent
+    type ParentDependencies = (Self,);
+
+    type ChildDependencies = ();
+
+    type NodeDependencies = ();
+
+    // TextColor only cares about the color attribute of the current node
+    const NODE_MASK: NodeMaskBuilder<'static> =
+        // Get access to the color attribute
+        NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["color"]));
+
+    fn update<'a>(
+        &mut self,
+        node_view: NodeView<()>,
+        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
+        _context: &SendAnyMap,
+    ) -> bool {
+        // TextColor only depends on the color tag, so getting the first tag is equivilent to looking through all tags
+        let new = match node_view
+            .attributes()
+            .and_then(|mut attrs| attrs.next())
+            .and_then(|attr| attr.value.as_text())
+        {
+            // if there is a color tag, translate it
+            Some("red") => TextColor { r: 255, g: 0, b: 0 },
+            Some("green") => TextColor { r: 0, g: 255, b: 0 },
+            Some("blue") => TextColor { r: 0, g: 0, b: 255 },
+            Some(color) => panic!("unknown color {color}"),
+            // otherwise check if the node has a parent and inherit that color
+            None => match parent {
+                Some((parent,)) => *parent,
+                None => Self::default(),
+            },
+        };
+        // check if the member has changed
+        let changed = new != *self;
+        *self = new;
+        changed
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Default, Component)]
+struct Border(bool);
+
+#[partial_derive_state]
+impl State for Border {
+    // TextColor depends on the TextColor part of the parent
+    type ParentDependencies = (Self,);
+
+    type ChildDependencies = ();
+
+    type NodeDependencies = ();
+
+    // Border does not depended on any other member in the current node
+    const NODE_MASK: NodeMaskBuilder<'static> =
+        // Get access to the border attribute
+        NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["border"]));
+
+    fn update<'a>(
+        &mut self,
+        node_view: NodeView<()>,
+        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
+        _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(),
+        );
+        // check if the member has changed
+        let changed = new != *self;
+        *self = new;
+        changed
+    }
+}
+}
+
+

Now that we have our state, we can put it to use in our RealDom. We can update the RealDom with apply_mutations to update the structure of the dom (adding, removing, and changing properties of nodes) and then update_state to update the States for each of the nodes that changed.

+
fn main() -> Result<(), Box<dyn std::error::Error>> {
+    fn app(cx: Scope) -> Element {
+        let count = use_state(cx, || 0);
+
+        use_future(cx, (count,), |(count,)| async move {
+            loop {
+                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+                count.set(*count + 1);
+            }
+        });
+
+        cx.render(rsx! {
+            div{
+                color: "red",
+                "{count}"
+            }
+        })
+    }
+
+    // create the vdom, the real_dom, and the binding layer between them
+    let mut vdom = VirtualDom::new(app);
+    let mut rdom: RealDom = RealDom::new([
+        Border::to_type_erased(),
+        TextColor::to_type_erased(),
+        Size::to_type_erased(),
+    ]);
+    let mut dioxus_intigration_state = DioxusState::create(&mut rdom);
+
+    let mutations = vdom.rebuild();
+    // update the structure of the real_dom tree
+    dioxus_intigration_state.apply_mutations(&mut rdom, mutations);
+    let mut ctx = SendAnyMap::new();
+    // set the font size to 3.3
+    ctx.insert(FontSize(3.3));
+    // update the State for nodes in the real_dom tree
+    let _to_rerender = rdom.update_state(ctx);
+
+    // we need to run the vdom in a async runtime
+    tokio::runtime::Builder::new_current_thread()
+        .enable_all()
+        .build()?
+        .block_on(async {
+            loop {
+                // wait for the vdom to update
+                vdom.wait_for_work().await;
+
+                // get the mutations from the vdom
+                let mutations = vdom.render_immediate();
+
+                // update the structure of the real_dom tree
+                dioxus_intigration_state.apply_mutations(&mut rdom, mutations);
+
+                // update the state of the real_dom tree
+                let mut ctx = SendAnyMap::new();
+                // set the font size to 3.3
+                ctx.insert(FontSize(3.3));
+                let _to_rerender = rdom.update_state(ctx);
+
+                // render...
+                rdom.traverse_depth_first(|node| {
+                    let indent = " ".repeat(node.height() as usize);
+                    let color = *node.get::<TextColor>().unwrap();
+                    let size = *node.get::<Size>().unwrap();
+                    let border = *node.get::<Border>().unwrap();
+                    let id = node.id();
+                    let node = node.node_type();
+                    let node_type = &*node;
+                    println!("{indent}{id:?} {color:?} {size:?} {border:?} {node_type:?}");
+                });
+            }
+        })
+}
+
+

Layout

+

For most platforms, the layout of the Elements will stay the same. The layout_attributes module provides a way to apply HTML attributes a Taffy layout style.

+

Text Editing

+

To make it easier to implement text editing in rust renderers, native-core also contains a renderer-agnostic cursor system. The cursor can handle text editing, selection, and movement with common keyboard shortcuts integrated.

+

+#![allow(unused)]
+fn main() {
+fn text_editing() {
+    let mut cursor = Cursor::default();
+    let mut text = String::new();
+
+    // handle keyboard input with a max text length of 10
+    cursor.handle_input(
+        &Code::ArrowRight,
+        &Key::ArrowRight,
+        &Modifiers::empty(),
+        &mut text,
+        10,
+    );
+
+    // mannually select text between characters 0-5 on the first line (this could be from dragging with a mouse)
+    cursor.start = Pos::new(0, 0);
+    cursor.end = Some(Pos::new(5, 0));
+
+    // delete the selected text and move the cursor to the start of the selection
+    cursor.delete_selection(&mut text);
+}
+}
+
+

Conclusion

+

That should be it! You should have nearly all the knowledge required on how to implement your renderer. We're super interested in seeing Dioxus apps brought to custom desktop renderers, mobile renderers, video game UI, and even augmented reality! If you're interested in contributing to any of these projects, don't be afraid to reach out or join the community.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/describing_ui/component_children.html b/docs/nightly/guide/en/describing_ui/component_children.html new file mode 100644 index 000000000..497fb766f --- /dev/null +++ b/docs/nightly/guide/en/describing_ui/component_children.html @@ -0,0 +1,292 @@ + + + + + + Component Children + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Component Children

+

In some cases, you may wish to create a component that acts as a container for some other content, without the component needing to know what that content is. To achieve this, create a prop of type Element:

+

+#![allow(unused)]
+fn main() {
+#[derive(Props)]
+struct ClickableProps<'a> {
+    href: &'a str,
+    body: Element<'a>,
+}
+
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
+    cx.render(rsx!(
+        a {
+            href: "{cx.props.href}",
+            class: "fancy-button",
+            &cx.props.body
+        }
+    ))
+}
+}
+
+

Then, when rendering the component, you can pass in the output of cx.render(rsx!(...)):

+

+#![allow(unused)]
+fn main() {
+    cx.render(rsx! {
+        Clickable {
+            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
+            body: cx.render(rsx!("How to " i {"not"} " be seen")),
+        }
+    })
+}
+
+
+

Note: Since Element<'a> is a borrowed prop, there will be no memoization.

+
+
+

Warning: While it may compile, do not include the same Element more than once in the RSX. The resulting behavior is unspecified.

+
+

The children field

+

Rather than passing the RSX through a regular prop, you may wish to accept children similarly to how elements can have children. The "magic" children prop lets you achieve this:

+

+#![allow(unused)]
+fn main() {
+#[derive(Props)]
+struct ClickableProps<'a> {
+    href: &'a str,
+    children: Element<'a>,
+}
+
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
+    cx.render(rsx!(
+        a {
+            href: "{cx.props.href}",
+            class: "fancy-button",
+            &cx.props.children
+        }
+    ))
+}
+}
+
+

This makes using the component much simpler: simply put the RSX inside the {} brackets – and there is no need for a render call or another macro!

+

+#![allow(unused)]
+fn main() {
+    cx.render(rsx! {
+        Clickable {
+            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
+            "How to " i {"not"} " be seen"
+        }
+    })
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/describing_ui/component_props.html b/docs/nightly/guide/en/describing_ui/component_props.html new file mode 100644 index 000000000..29414b577 --- /dev/null +++ b/docs/nightly/guide/en/describing_ui/component_props.html @@ -0,0 +1,466 @@ + + + + + + Props + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Component Props

+

Just like you can pass arguments to a function, you can pass props to a component that customize its behavior! The components we've seen so far didn't accept any props – so let's write some components that do.

+

#[derive(Props)]

+

Component props are a single struct annotated with #[derive(Props)]. For a component to accept props, the type of its argument must be Scope<YourPropsStruct>. Then, you can access the value of the props using cx.props.

+

There are 2 flavors of Props structs:

+
    +
  • Owned props: +
      +
    • Don't have an associated lifetime
    • +
    • Implement PartialEq, allow for memoization (if the props don't change, Dioxus won't re-render the component)
    • +
    +
  • +
  • Borrowed props: +
      +
    • Borrow from a parent component
    • +
    • Cannot be memoized due to lifetime constraints
    • +
    +
  • +
+

Owned Props

+

Owned Props are very simple – they don't borrow anything. Example:

+

+#![allow(unused)]
+fn main() {
+// Remember: Owned props must implement `PartialEq`!
+#[derive(PartialEq, Props)]
+struct LikesProps {
+    score: i32,
+}
+
+fn Likes(cx: Scope<LikesProps>) -> Element {
+    cx.render(rsx! {
+        div {
+            "This post has ",
+            b { "{cx.props.score}" },
+            " likes"
+        }
+    })
+}
+}
+
+

You can then pass prop values to the component the same way you would pass attributes to an element:

+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Likes {
+            score: 42,
+        },
+    })
+}
+}
+
+

Screenshot: Likes component

+

Borrowed Props

+

Owned props work well if your props are easy to copy around – like a single number. But what if we need to pass a larger data type, like a String from an App Component to a TitleCard subcomponent? A naive solution might be to .clone() the String, creating a copy of it for the subcomponent – but this would be inefficient, especially for larger Strings.

+

Rust allows for something more efficient – borrowing the String as a &str – this is what Borrowed Props are for!

+

+#![allow(unused)]
+fn main() {
+#[derive(Props)]
+struct TitleCardProps<'a> {
+    title: &'a str,
+}
+
+fn TitleCard<'a>(cx: Scope<'a, TitleCardProps<'a>>) -> Element {
+    cx.render(rsx! {
+        h1 { "{cx.props.title}" }
+    })
+}
+}
+
+

We can then use the component like this:

+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    let hello = "Hello Dioxus!";
+
+    cx.render(rsx!(TitleCard { title: hello }))
+}
+}
+
+

Screenshot: TitleCard component

+

Borrowed props can be very useful, but they do not allow for memorization so they will always rerun when the parent scope is rerendered. Because of this Borrowed Props should be reserved for components that are cheap to rerun or places where cloning data is an issue. Using Borrowed Props everywhere will result in large parts of your app rerunning every interaction.

+

Prop Options

+

The #[derive(Props)] macro has some features that let you customize the behavior of props.

+

Optional Props

+

You can create optional fields by using the Option<…> type for a field:

+

+#![allow(unused)]
+fn main() {
+#[derive(Props)]
+struct OptionalProps<'a> {
+    title: &'a str,
+    subtitle: Option<&'a str>,
+}
+
+fn Title<'a>(cx: Scope<'a, OptionalProps>) -> Element<'a> {
+    cx.render(rsx!(h1{
+        "{cx.props.title}: ",
+        cx.props.subtitle.unwrap_or("No subtitle provided"),
+    }))
+}
+}
+
+

Then, you can choose to either provide them or not:

+

+#![allow(unused)]
+fn main() {
+Title {
+    title: "Some Title",
+},
+Title {
+    title: "Some Title",
+    subtitle: "Some Subtitle",
+},
+// Providing an Option explicitly won't compile though:
+// Title {
+//     title: "Some Title",
+//     subtitle: None,
+// },
+}
+
+

Explicitly Required Options

+

If you want to explicitly require an Option, and not an optional prop, you can annotate it with #[props(!optional)]:

+

+#![allow(unused)]
+fn main() {
+#[derive(Props)]
+struct ExplicitOptionProps<'a> {
+    title: &'a str,
+    #[props(!optional)]
+    subtitle: Option<&'a str>,
+}
+
+fn ExplicitOption<'a>(cx: Scope<'a, ExplicitOptionProps>) -> Element<'a> {
+    cx.render(rsx!(h1 {
+        "{cx.props.title}: ",
+        cx.props.subtitle.unwrap_or("No subtitle provided"),
+    }))
+}
+}
+
+

Then, you have to explicitly pass either Some("str") or None:

+

+#![allow(unused)]
+fn main() {
+ExplicitOption {
+    title: "Some Title",
+    subtitle: None,
+},
+ExplicitOption {
+    title: "Some Title",
+    subtitle: Some("Some Title"),
+},
+// This won't compile:
+// ExplicitOption {
+//     title: "Some Title",
+// },
+}
+
+

Default Props

+

You can use #[props(default = 42)] to make a field optional and specify its default value:

+

+#![allow(unused)]
+fn main() {
+#[derive(PartialEq, Props)]
+struct DefaultProps {
+    // default to 42 when not provided
+    #[props(default = 42)]
+    number: i64,
+}
+
+fn DefaultComponent(cx: Scope<DefaultProps>) -> Element {
+    cx.render(rsx!(h1 { "{cx.props.number}" }))
+}
+}
+
+

Then, similarly to optional props, you don't have to provide it:

+

+#![allow(unused)]
+fn main() {
+DefaultComponent {
+    number: 5,
+},
+DefaultComponent {},
+}
+
+

Automatic Conversion with .into

+

It is common for Rust functions to accept impl Into<SomeType> rather than just SomeType to support a wider range of parameters. If you want similar functionality with props, you can use #[props(into)]. For example, you could add it on a String prop – and &str will also be automatically accepted, as it can be converted into String:

+

+#![allow(unused)]
+fn main() {
+#[derive(PartialEq, Props)]
+struct IntoProps {
+    #[props(into)]
+    string: String,
+}
+
+fn IntoComponent(cx: Scope<IntoProps>) -> Element {
+    cx.render(rsx!(h1 { "{cx.props.string}" }))
+}
+}
+
+

Then, you can use it so:

+

+#![allow(unused)]
+fn main() {
+IntoComponent {
+    string: "some &str",
+},
+}
+
+

The inline_props macro

+

So far, every Component function we've seen had a corresponding ComponentProps struct to pass in props. This was quite verbose... Wouldn't it be nice to have props as simple function arguments? Then we wouldn't need to define a Props struct, and instead of typing cx.props.whatever, we could just use whatever directly!

+

inline_props allows you to do just that. Instead of typing the "full" version:

+

+#![allow(unused)]
+fn main() {
+#[derive(Props, PartialEq)]
+struct TitleCardProps {
+    title: String,
+}
+
+fn TitleCard(cx: Scope<TitleCardProps>) -> Element {
+    cx.render(rsx!{
+        h1 { "{cx.props.title}" }
+    })
+}
+}
+
+

...you can define a function that accepts props as arguments. Then, just annotate it with #[inline_props], and the macro will turn it into a regular Component for you:

+

+#![allow(unused)]
+fn main() {
+#[inline_props]
+fn TitleCard(cx: Scope, title: String) -> Element {
+    cx.render(rsx!{
+        h1 { "{title}" }
+    })
+}
+}
+
+
+

While the new Component is shorter and easier to read, this macro should not be used by library authors since you have less control over Prop documentation.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/describing_ui/components.html b/docs/nightly/guide/en/describing_ui/components.html new file mode 100644 index 000000000..d5eb911f1 --- /dev/null +++ b/docs/nightly/guide/en/describing_ui/components.html @@ -0,0 +1,265 @@ + + + + + + Components + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Components

+

Just like you wouldn't want to write a complex program in a single, long, main function, you shouldn't build a complex UI in a single App function. Instead, you should break down the functionality of an app in logical parts called components.

+

A component is a Rust function, named in UpperCammelCase, that takes a Scope parameter and returns an Element describing the UI it wants to render. In fact, our App function is a component!

+

+#![allow(unused)]
+fn main() {
+// define a component that renders a div with the text "Hello, world!"
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            "Hello, world!"
+        }
+    })
+}
+}
+
+
+

You'll probably want to add #![allow(non_snake_case)] to the top of your crate to avoid warnings about UpperCammelCase component names

+
+

A Component is responsible for some rendering task – typically, rendering an isolated part of the user interface. For example, you could have an About component that renders a short description of Dioxus Labs:

+

+#![allow(unused)]
+fn main() {
+pub fn About(cx: Scope) -> Element {
+    cx.render(rsx!(p {
+        b {"Dioxus Labs"}
+        " An Open Source project dedicated to making Rust UI wonderful."
+    }))
+}
+}
+
+

Then, you can render your component in another component, similarly to how elements are rendered:

+

+#![allow(unused)]
+fn main() {
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        About {},
+        About {},
+    })
+}
+}
+
+

Screenshot containing the About component twice

+
+

At this point, it might seem like components are nothing more than functions. However, as you learn more about the features of Dioxus, you'll see that they are actually more powerful!

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/describing_ui/images/component_borrowed_props_screenshot.png b/docs/nightly/guide/en/describing_ui/images/component_borrowed_props_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..6f1864662f34cf7bc4101f2778f0ccb03d1d1646 GIT binary patch literal 7868 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/describing_ui/images/component_owned_props_screenshot.png b/docs/nightly/guide/en/describing_ui/images/component_owned_props_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..2a1146cd1d49b2b54bcb1d103f69a294d3921ec9 GIT binary patch literal 6318 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/describing_ui/images/screenshot_about_component.png b/docs/nightly/guide/en/describing_ui/images/screenshot_about_component.png new file mode 100644 index 0000000000000000000000000000000000000000..36f7250a1bbb007bf4f3cea787319d9df08f7b8d GIT binary patch literal 19470 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/describing_ui/index.html b/docs/nightly/guide/en/describing_ui/index.html new file mode 100644 index 000000000..f63ed5fad --- /dev/null +++ b/docs/nightly/guide/en/describing_ui/index.html @@ -0,0 +1,404 @@ + + + + + + Describing the UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Describing the UI

+

Dioxus is a declarative framework. This means that instead of telling Dioxus what to do (e.g. to "create an element" or "set the color to red") we simply declare what we want the UI to look like using RSX.

+

You have already seen a simple example of RSX syntax in the "hello world" application:

+

+#![allow(unused)]
+fn main() {
+// define a component that renders a div with the text "Hello, world!"
+fn App(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            "Hello, world!"
+        }
+    })
+}
+}
+
+

Here, we use the rsx! macro to declare that we want a div element, containing the text "Hello, world!". Dioxus takes the RSX and constructs a UI from it.

+

RSX Features

+

RSX is very similar to HTML in that it describes elements with attributes and children. Here's an empty div element in RSX, as well as the resulting HTML:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!(div {
+    // attributes / listeners
+    // children
+}))
+}
+
+
<div></div>
+
+

Attributes

+

Attributes (and listeners) modify the behavior or appearance of the element they are attached to. They are specified inside the {} brackets, using the name: value syntax. You can provide the value as a literal in the RSX:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!(a {
+    href: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
+    class: "primary_button",
+    color: "red",
+}))
+}
+
+
<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" class="primary_button" autofocus="true" style="color: red"></a>
+
+
+

Note: All attributes defined in dioxus-html follow the snake_case naming convention. They transform their snake_case names to HTML's camelCase attributes.

+
+
+

Note: Styles can be used directly outside of the style: attribute. In the above example, color: "red" is turned into style="color: red".

+
+

Custom Attributes

+

Dioxus has a pre-configured set of attributes that you can use. RSX is validated at compile time to make sure you didn't specify an invalid attribute. If you want to override this behavior with a custom attribute name, specify the attribute in quotes:

+

+#![allow(unused)]
+fn main() {
+    cx.render(rsx!(b {
+        "customAttribute": "value",
+    }))
+}
+
+
<b customAttribute="value">
+</b>
+
+

Interpolation

+

Similarly to how you can format Rust strings, you can also interpolate in RSX text. Use {variable} to Display the value of a variable in a string, or {variable:?} to use the Debug representation:

+

+#![allow(unused)]
+fn main() {
+let coordinates = (42, 0);
+let country = "es";
+cx.render(rsx!(div {
+    class: "country-{country}",
+    "position": "{coordinates:?}",
+    // arbitrary expressions are allowed,
+    // as long as they don't contain `{}`
+    div {
+        "{country.to_uppercase()}"
+    },
+    div {
+        "{7*6}"
+    },
+    // {} can be escaped with {{}}
+    div {
+        "{{}}"
+    },
+}))
+}
+
+
<div class="country-es" position="(42, 0)">
+    <div>ES</div>
+    <div>42</div>
+    <div>{}</div>
+</div>
+
+

Children

+

To add children to an element, put them inside the {} brackets after all attributes and listeners in the element. They can be other elements, text, or components. For example, you could have an ol (ordered list) element, containing 3 li (list item) elements, each of which contains some text:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!(ol {
+    li {"First Item"}
+    li {"Second Item"}
+    li {"Third Item"}
+}))
+}
+
+
<ol>
+    <li>First Item</li>
+    <li>Second Item</li>
+    <li>Third Item</li>
+</ol>
+
+

Fragments

+

You can render multiple elements at the top level of rsx! and they will be automatically grouped.

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!(
+    p {"First Item"},
+    p {"Second Item"},
+))
+}
+
+
<p>First Item</p>
+<p>Second Item</p>
+
+

Expressions

+

You can include arbitrary Rust expressions as children within RSX that implements IntoDynNode. This is useful for displaying data from an iterator:

+

+#![allow(unused)]
+fn main() {
+let text = "Dioxus";
+cx.render(rsx!(span {
+    text.to_uppercase(),
+    // create a list of text from 0 to 9
+    (0..10).map(|i| rsx!{ i.to_string() })
+}))
+}
+
+
<span>DIOXUS0123456789</span>
+
+

Loops

+

In addition to iterators you can also use for loops directly within RSX:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!{
+    // use a for loop where the body itself is RSX
+    div {
+        // create a list of text from 0 to 9
+        for i in 0..3 {
+            // NOTE: the body of the loop is RSX not a rust statement
+            div {
+                "{i}"
+            }
+        }
+    }
+    // iterator equivalent
+    div {
+        (0..3).map(|i| rsx!{ div { "{i}" } })
+    }
+})
+}
+
+
<div>0</div>
+<div>1</div>
+<div>2</div>
+<div>0</div>
+<div>1</div>
+<div>2</div>
+
+

If statements

+

You can also use if statements without an else branch within RSX:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx!{
+    // use if statements without an else
+    if true {
+        rsx!(div { "true" })
+    }
+})
+}
+
+
<div>true</div>
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/describing_ui/special_attributes.html b/docs/nightly/guide/en/describing_ui/special_attributes.html new file mode 100644 index 000000000..1cb196b66 --- /dev/null +++ b/docs/nightly/guide/en/describing_ui/special_attributes.html @@ -0,0 +1,286 @@ + + + + + + Special Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Special Attributes

+

While most attributes are simply passed on to the HTML, some have special behaviors.

+

The HTML Escape Hatch

+

If you're working with pre-rendered assets, output from templates, or output from a JS library, then you might want to pass HTML directly instead of going through Dioxus. In these instances, reach for dangerous_inner_html.

+

For example, shipping a markdown-to-Dioxus converter might significantly bloat your final application size. Instead, you'll want to pre-render your markdown to HTML and then include the HTML directly in your output. We use this approach for the Dioxus homepage:

+

+#![allow(unused)]
+fn main() {
+// this should come from a trusted source
+let contents = "live <b>dangerously</b>";
+
+cx.render(rsx! {
+    div {
+        dangerous_inner_html: "{contents}",
+    }
+})
+}
+
+
+

Note! This attribute is called "dangerous_inner_html" because it is dangerous to pass it data you don't trust. If you're not careful, you can easily expose cross-site scripting (XSS) attacks to your users.

+

If you're handling untrusted input, make sure to sanitize your HTML before passing it into dangerous_inner_html – or just pass it to a Text Element to escape any HTML tags.

+
+

Boolean Attributes

+

Most attributes, when rendered, will be rendered exactly as the input you provided. However, some attributes are considered "boolean" attributes and just their presence determines whether they affect the output. For these attributes, a provided value of "false" will cause them to be removed from the target element.

+

So this RSX wouldn't actually render the hidden attribute:

+

+#![allow(unused)]
+fn main() {
+cx.render(rsx! {
+    div {
+        hidden: "false",
+        "hello"
+    }
+})
+}
+
+
<div>hello</div>
+
+

Not all attributes work like this however. Only the following attributes have this behavior:

+
    +
  • allowfullscreen
  • +
  • allowpaymentrequest
  • +
  • async
  • +
  • autofocus
  • +
  • autoplay
  • +
  • checked
  • +
  • controls
  • +
  • default
  • +
  • defer
  • +
  • disabled
  • +
  • formnovalidate
  • +
  • hidden
  • +
  • ismap
  • +
  • itemscope
  • +
  • loop
  • +
  • multiple
  • +
  • muted
  • +
  • nomodule
  • +
  • novalidate
  • +
  • open
  • +
  • playsinline
  • +
  • readonly
  • +
  • required
  • +
  • reversed
  • +
  • selected
  • +
  • truespeed
  • +
+

For any other attributes, a value of "false" will be sent directly to the DOM.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/editor.js b/docs/nightly/guide/en/editor.js new file mode 100644 index 000000000..464790c49 --- /dev/null +++ b/docs/nightly/guide/en/editor.js @@ -0,0 +1,29 @@ +"use strict"; +window.editors = []; +(function(editors) { + if (typeof(ace) === 'undefined' || !ace) { + return; + } + + Array.from(document.querySelectorAll('.editable')).forEach(function(editable) { + let display_line_numbers = window.playground_line_numbers || false; + + let editor = ace.edit(editable); + editor.setOptions({ + highlightActiveLine: false, + showPrintMargin: false, + showLineNumbers: display_line_numbers, + showGutter: display_line_numbers, + maxLines: Infinity, + fontSize: "0.875em" // please adjust the font size of the code in general.css + }); + + editor.$blockScrolling = Infinity; + + editor.getSession().setMode("ace/mode/rust"); + + editor.originalCode = editor.getValue(); + + editors.push(editor); + }); +})(window.editors); diff --git a/docs/nightly/guide/en/elasticlunr.min.js b/docs/nightly/guide/en/elasticlunr.min.js new file mode 100644 index 000000000..94b20dd2e --- /dev/null +++ b/docs/nightly/guide/en/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 + * + * Copyright (C) 2017 Oliver Nightingale + * Copyright (C) 2017 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.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 A;{X5v literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/favicon.svg b/docs/nightly/guide/en/favicon.svg new file mode 100644 index 000000000..90e0ea58b --- /dev/null +++ b/docs/nightly/guide/en/favicon.svg @@ -0,0 +1,22 @@ + + + + + diff --git a/docs/nightly/guide/en/fonts/OPEN-SANS-LICENSE.txt b/docs/nightly/guide/en/fonts/OPEN-SANS-LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/docs/nightly/guide/en/fonts/OPEN-SANS-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/docs/nightly/guide/en/fonts/SOURCE-CODE-PRO-LICENSE.txt b/docs/nightly/guide/en/fonts/SOURCE-CODE-PRO-LICENSE.txt new file mode 100644 index 000000000..366206f54 --- /dev/null +++ b/docs/nightly/guide/en/fonts/SOURCE-CODE-PRO-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/nightly/guide/en/fonts/fonts.css b/docs/nightly/guide/en/fonts/fonts.css new file mode 100644 index 000000000..858efa598 --- /dev/null +++ b/docs/nightly/guide/en/fonts/fonts.css @@ -0,0 +1,100 @@ +/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ +/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ + +/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), + url('open-sans-v17-all-charsets-300.woff2') format('woff2'); +} + +/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), + url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); +} + +/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); +} + +/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); +} + +/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('open-sans-v17-all-charsets-600.woff2') format('woff2'); +} + +/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), + url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); +} + +/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('open-sans-v17-all-charsets-700.woff2') format('woff2'); +} + +/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), + url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); +} + +/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('open-sans-v17-all-charsets-800.woff2') format('woff2'); +} + +/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), + url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); +} + +/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); +} diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-300.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-300.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9f51be370fa913ce6de2922b580c262c4822b337 GIT binary patch literal 44352 zcmV(;K-<4}Pew8T0RR910Ifg(5dZ)H0f7hr0Ib{q0RR9100000000000000000000 z0000QE*lUWfmQ}!0EY+&fhq})G!YOAg!yQMtSAeP3IG8%0we>R0t6rhgFFYi4Ge-h zTM$x_K;*{m=TyO<(oF`$dr#+gT@uRz<@OP72f1way{Ld4djxa`IG0*=K;{4c|Nq>i zF~-^s+Z{rPn$}0zLzV=G*ddk#MfRZCOSo7Svxg)@O1QTM(GtC{-8am>TkfXJ&}5JO zXokZnNWAaG&x#r1r&DFc3k@sfl$|@RDaX?kWW{EN@TZnHp}gCDd}u9PW@H>gZ142z+QEhtr+J1&#|>KAj6Y2`)3tZkBe+ebjmTS6=W*;+$iHPBB3Un)Qo?6q*dE(P3T9y565vHowfyevYxI9K2P(y z$<_L{@8?J5hBF;TxvX%vUMY{MW;AQOFw;MRE?UNs>(i)Pw#F30SO&%}gA&nV#5ynh z%lr4w|41^EwI78NR7X_&MdMPeXq|gj4oJ6}tzd{4Fvwwq1Zjy_sfS1l0YYgJLOuSa zG~qZt#{MG5VL1;uY?c0qywYwhjn*_`$CiZFZCFDFz-?kG;zz}gkK?(Z;(4Ip0|Y@p zL`0q-DhfWlFW)O~_Uv1l(z*7n%=kiif-51?{(S1>dTz;-%RXz{zW_NG4POWVdSfQ{H?gb&VPWmSuI@as@lXQ zCML+EVq_sv+K31qR)E!rHdbOZcI*#x`rpX1-FQZd2?w2J5+HD^d^xN_9WLUu;R1_>$Sl2l1j{i_PqRoxBKXmEfAv5RRCG~gHz zoRPqp)jl)`>4DtY_ee=+oD0vBlrtv1+}R|)Aj>WYFNl--dsEGJL13vB!x?g=A&fDlOONKn#&pyZ<<^Gt#Y5O9+B{||V8CFK!GIY^G7 ziird-fZ=XPfYkAzOvx!^1&5rvR8_9Zlqy%TZCti4x_G(NsHD}UoUD}Q&&1ywU=hnR zK_eK;d!w1V-89?ZEBgl|7bFMOFTBI&;bU#pwZ9KM5d*ckoOlTrnn@#e=0bxf_LKF$ zd-0Mi4MXYT*CGx?Tq%ZXXdY`yIWWVJf|?K(5DNrL%GP_mZs@nw-vBb}Rw0W;wB!)N z5TjzUSNZXIA7943^nXK*r#Dw9|Mtf&ksu-=h_`Yp9V;Dkh;8<4psUZVb-$?#qp%T! ziAdB1b$5t5hjOzR8iD$*)2$e71R6>Zt8%DEY$Sg2KWN&b4Cqr8h>8`6#((@8#L}XktLaTS zryU~vMx03nNxOB%uQY)H>VL7pz)zP2nhY%8WH@)-0RsdY-07d0c5ee-ah{%=QSM%u z*8so2)#K3GU!m!|?O$6+?&yD~(Fj>ZOxK05BApxGi zJr7YET6WG{j1#TYt(MkW%SPIA4dOUU&zsN+<{}nS6r*LQrr)v8tl?2R`* z6w<>(odO>Dg>%+<`=H~%Re+D2bI267Gb@WPo}vT*tKEȮck{9tEK*~BMoW% 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-300italic.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-300italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2f545448418cba6668a2e7d49e9616e8c69dfd15 GIT binary patch literal 40656 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 bQBM5)6s%p?oy_T)fR3IrepgG2|qH4K6n zTjEWT0M>3h@}ENV+_q{F9wW<-3brc`y_pI_^4p(Ua9sB|0Gw|m`2YX^KRubqVVATn zNekEj{BQrDNslN|DcXpZA-X^~dK8u+%2-5Irnagte8a?(^PQHDA{Ia>x8E;>s=qh`PM9HJ1<#&OtZjf!-5cTIED~WWHDzI$2&YI z-Qx_U$EM$KlLl(PE)LgB-E!IUkaA<%CtwLP6`45Di)=MXIdNdHSN3iVq9AM zW$$vH*PwWVFLy0m^MBLs2Du(884Xzm#x8>rZHyHsULO9fi|@W9RUh;~&`vmeNlSn| zUHLy%^$r9js)H)+Tt0XPT}agq13U(brxo75{lYd9v2}uZ*SGtHwrP4Q94xD5SfeTcynoRZcTmcB! z|IfY6+?N7SQU=}gLr|c!mS};%tuf1*^*R&=&=|m9$hm)94|)`EAy7sg+xyU<5&T>+PVPD728Hda7D(-wSBu5C)Gdv)`@3pXOX&?kiFF%}^ak}Y4e z9%ulKM*G*#kQ{P2PSURDcV7BVoGo!}kX#h5!tBxwFV2n!&FB6pSFL=Pz-G405@Oh& zzi+kWu_v%=2*Ii)=%g>6FsPyoCW>8L2Tkhu^eDIftLh{`s=8@1{J(1Fy&Xb=%o|3) zpZJi}CE=~Y%&KeTn@ztzN2m0_=(M`)pPv5zewuEd;Ey%bNVzpE#INw&t2k?nvi2Q-?3EO}B}9?*MVKF5;nz(9yr1prxgCmMxh$w^EhIY{6D zF3ZcN>)j+J-gdFuv}e!%zp8$^X4Iz}fMKkT6rrIs)dW*JM zKbqQ0SMzp$k*q6C=>-MAV-8#BAm&@|ME`4N&iSP@lmgH>NKUJQKZsYr1H&pqAs~q0 z@I23cvtsXG@Wi2Is7WnJt2%94%sa~#IzWae{EhX`y?BX{n4xqBnv{(>DaBBIto3|h zfYxgxLPhG&a+=#*%jGQbs}UiJXgJefpHP8xD8@;AI(0BY7!x|Y@A?1#{2S?c-!<7w zMMYIbMMXr_v_C%YGN!e#^Y(u?SYZdk2X&_l*=NWY#<>=9l5ASeUMMAp(fker8VosLx@B&L&j#7*0l3cc_Y%PiDbiC znq_muF3v_)zKIPAq`5)LWS^0k&iS=&tXr9C@l#Ytp6LBabDVCmNkLU5q8K6qcPVWHIMBuRYSXvRHJ= zm$~xUxT-(UKl6R%`^j$#1p-xY1#*ywVHks1n1>P^g41vj?kqc&y)%Vih1#uxnp5-Y zp!y&uLfJwkLgl&s+?8A*XXlo48``Vi?q8rj;U@J)g#<3T&7xA0nnc`{=bIg|5wX}>R8SI)bT|x{~1f00nIQ~ zF97vA-B=GobMi zKMo{dg$W&0Aoc(K@1Od{m&R6E0LWUa@SuFYpX0^$J;ptccE6q2a(FR34Et%w5EX_{ z=>w_^quNK*_=MU6AD;jYS{Qx#bf1%AJn3PV~S>7F4$6__XUyaab_{e5$&(L0;2g`U3613b^K zhH^f`Ek#ug66HW?0n}}sRAS+mj((b~HJaQ!Y=l*kG&ViSCVVR1;IAa~#v)DY(hV_t ztB~CC=fU8X2o7*#>k=iVs@`#}jIF#hCL|{9cc4wI4{?QnSiOejiIIK=-U_4)a~ z1A2gL7U&v4$wa#4s#rI(xaG&ODuWg0R#3aB?#-{R@HlC1j&BPekZia}+dt&lDMRat zhl*dJvz`sQtt|&THt#xxG*_S!G_2+8m$*93)a=yz+8CE0SZ`vTqXSj7NBgvd#1|ilzpx)ea^NUqpX$l@ghY1G{EW}LhxvXe6FaI z{%1Uo+p{n;^q#<$Mvux6^u{dF7l%M=RS7GyJNC*sTdJeCR%@ z^kQ`nT2-_Q*6_&=7xmIZNe?`?Dw5%$U@`F5Ff6U=b8v{if}Py(GRW5y;kG-M&A%Nx zO(gz)Y9>bltWkOm%i4?Vo;DC6cIfH~eS^CCO0v(25&JMOeZP*A!Lk~KlkM3+G~rZvoH8ON%` zQr>`6Dn+m!%G{VQrU%uV(rRjT)_-8@G(&HujFj=_AJ;Vyho$L2&Qe$D?W$zjOktu* zu`?T0rg~<;;Vz{<4=;IWA`v^`^vhG> zGX3&QdWbWH5bnzz_gjfdrf+!3HILaukY_mwQs~S9FqB)6%hWw~rjO*0Ioa{Pn)@|M zhR$RRf+o2N$6VfWVA14)z6fhtCSN63kPzFQrZ=YbjNYI(ODz&hXrKHR4}F#dO(c(+ zX$!5RYJRI;%j&0y%O>J#q}ocPh(xkYFGT{(?0Sft{JIMZK>m*!c~BJ=?JL7&gWL9z0?Q zV7AJtGBi1M0HGw+K=#}RtR@MW`z55wjnXtu2wGY;L?u=zQl~Y(VEib~wSD+&apr4uR;QLsaxi;kl$Ez24a*vqVmKNhFb-z7L>C_|^UFNn&y8Wr@=QOdy* zWou$Tl1e*&GhzG){qQ#vJ?>7~#E9^RJ$sIHakj_IRd61i1~vPI(h@y}gN%T`*)P=) ziYLOz_NdYR49b5DcU|ulPBpRdg=e@OM z%9jkBu^`e;-eca9+raInN5@tdX8`pS0M}))*21A707PWGOtKs}h9Pcvt_Ws-`)|3! z=F#U-&iUOo&oW4a6W{djI@cFOv?@->$uvNvI&Y+L8K2;~`o{Fk7`!T@w=y>M@_wu` zn0=KAt2NAqL@*#@f^*~!bY>d*J6U;8khn+-km;%^t}zBA5h$fbCZ>jhinXwg*9tB` zMKcwqy&R?$qcr1-CJh7@g{O?w%6;S=r2Beb55lU&N40oN3N3^1Gl#Cos9Otr}y`9ZR5BsIlaHERpX6zwYj&UNA-j1 z(~-?F36f51{q~$vv&o%I%QPZ#I;108{2_d_^bP1fjp#g@k$ye**@v6(=OW1r0AZ!E zw91L9oWmh9lqzibsz*i0b*26-bCnB2>r-TgF2Zz#{Qvrvf&m8jIaD5s{Z2K2F$eAZ~38U?aKHR%Knph`X|sW>We3O`(8x zRcMtlN!m`L_z1^U6DroHjJc$s=uT#f$8w8Zz8qa)@1-u?aWpVMDGJ=YB`R5RV07m; zCa{@*rmV+Pb2-S;r(!C|3R)dp`Kr$(J-i%=xairYaU!In`YiNnEOS_-zH$=(jsJ}1 z`eD0IVv^PHQ~6y5^u=5bnQyL$L&}n?2t94*gGaG2+BsBJSlQ>1Ow8r9_SQ&R{O)Tz zX9H*}TVFOrx+>N!WD4f-{Dz1LqkAekTF7g=B6$^eDpw$+Dlkytp2Qcm6L8z zlW=Is*>O{hK=@6-J1@nUNfa{(rmCO)!;x?4!N?UNM6)WLK=pd^{tX!_DL{tby@H*5 z9>%I2cyk-Kc4k+|-_OKksb`@AVlgx-Ex6)yk3n^2O#7MB$iTQpMK7Kv%PjVna2 zM1QBLWKWSF^*ho7Dzk#Em)xP4ElX3T7M5hpbtiYXFTaEKFNS}5rXmffUJ*`#Q+E~u z`-yh!5q@Gs4=2JnW-y@LiG!pzu`9)&c;c2x`AVs{#xZZYM^&93fkS=iY3}Z^x$;?i z?@gzyS7tCWi>01Tv~Tvs&%3&M1g*s%@hZkaCvYF~uAS!*?H%Xb$)PZ;89=EzRza0V zzfUK*3RvG*L9Fi0T;u*|4x*j-Wc&@*_JHYz-vb(6t6H3B8!%|NRER}sdQ|~tfCLD7 zVi>RiU|($EVB|Uxa!I;Yj#1pRo~h=;k_jp@t_e@X6#~w}4QpO7Xl`vnjYfV1uUNQ2 zN(oR2gGq2d1WeJ?S*Za=n6}E$e}KCio6L>kK~AyEZ!4l+SDt$~N^^{lnZBI0O3aF( zy*#d}!3sscxi7$20ajX^5(v=h=`^1ACev_s_BR%C5X4Tb!%i|7(2x{0P5ADf`O6Qm zE3uR{T!vn3oL~UwZLD`_i?bL)(;xs#1vGqV`}m9K-w%8kVeQ^G@SoB=3tE?eY%2Go zu_Y3TC~W?PLj7_lPvhwYKW60|{ZXu+uT94smi7R7ar~7dVRXjfG}iX}=1DZ4#na=z z>U`2(;h0(MkpjMlMge(e$I*R~Ze47q#-qB~@d(+goy`ZO5aVp(cmF<%r_Kl_(bY8g zAn($kY}9hSX}E4?nUbocA@w{4-hzZ^_DX{~{~TCm;B7{SJ>=(}RS8JWVh-Wu z);ZgGltz$PBmb;mCQF7Q6h}EAoS1ER9=^Dmwz)XvhbSnOdcVDe0o?S&&Pz{$D6X+4 z+i9lO|N3O0pXA*L#k_z;n#yp4f@S|v&6;pi;19Y38< z$jD%k53!xSyvdVMtcO*ZdocH`c$vLJCUbjhp5O-|qo;JA{~Yl%r* zg-mPU8uZtF`BF{FmfdrLIy7l12pmSfo`QZgxX?vZhXGx7t;=c#veZlQ)#9Zdp&}4! zv<3h~73s9EqDFg3xiyXOsj z!@wZITN}(xnRlEaA)o9Rz9ixSINWtLPMw>DgB)8_=>q8LR;fTB>OY|yAu?ftR#WWE zm_K>a9{&B@mB~n%10Pe-3#P9yJX>?GR{^U}SPpV%P2P9RrNNKM_dHP$3DN z``_2;G(VHU(H8&TSWBKZv|A+V+rosVHa=lY8ay$jm2$_W0dx}Rppehw$8{OkGYmjS z)5V#Ad>w2MnYVJdu~cN(@^(caO-4eDp|65qi<#BAxXBGpA#;&Q6bjmC=n70u1n(5V zRHC|SNf1)%mwpZE_q)q-vyT!m)?Ht3S%V|5YC4KSJM(W!TKQC=ab z=-7Mt)2?lJe&MNd7R=yI`m|tIjzdl4!*60}PlzCHv~j@C94cAItBe zUvwyxDXv1DcNa#o-id_}wBR20AEGjo+{6vf(f)Jz0$pP?x!eW%LHEtbqvJP~Fay=Q z+t1uUd){@qrgMDOEPP#k0$oyPrJ3XEM_BiyF%ICG;e~{daC`+WE!$+5^V}@-q=!|u zP9`S}K@3Wa*j`_%X1~a6vLO8G4~cNzK`RG{Cs6XiG*6lw@)bixt)@ z093V|23@OgnE~7aWf`&y1J6gfYkSL*YG2;DKUPuDBg2Jt- zo-}*Q{#|F}B%&2Lx;qvAT-{z}J?|BM_ufbUhsON)g~YblC8wiEinCz-^ZVwW$L_hg zdr#kY$-AppMDqP!#p*+1*YDji^A(7J7Cw#$e3p=}pYTSj*KP%}DgM2@APt&jc_)AT zd66kO2NQ=m&5+g~p_F!%q_@E-q5?b34EZh4nr;^{nMj&Dd3z>xgzo*ang)+moK4t9 zTjg{1u&x!`*F27mg9jFR{alD~Y=nZBJ|~PHRK2>_dj^VX4WJ~Xq|v_&eZdDk6H#X2 zULy|QUM>{ypws-9pvgauZjhgl(^lkhT_v``+M~k5xySCB7fZcz$(x4~^WCAMpm~KEoewsS+!%u5mnaT=UHZ9MVyx8`ME< zAY~nHO|0mP3*-c8Eu)5#B@VP*uher`Jv&V^tGvPt@^>H#3ET#KZrCP^%8X1zQg2sS z(jH{sH@PQsI#Q-k-LR&{#9XD{`BLojQcbX&>eHc$xeV&~U=M_@12|O+qHfh|Fn?2; z7;2(UzdP4snbVzgr54+~S553Ka%kw?gO1*{OWP!7Vm8M5i%MqO>SG8{y|zh4*I)CL zMuqdPKq`igmhiH1RK1&q&{aFDRtD%ZB-UZo_98mxxAX`Dka+YWUvGMlk@DP!x34pd$NuT&Jd5Z!AazY2>D>-k2Y=mxVG50H^{?A^U% zONb_!08SybnSqvw(CNVIYpaa3^XqDNy-vx}pXSqO1i5hmEv(7g`WyF-sMkTkmGM-p z$8>lt2+kXP-6+_r{);Ocrse!^Mm3bYIFGvsgu?$L?m3Qg8xADFKSqUO5;%|o4(-wR z@`1Dyl5R3UNwEu^dz%1I*we4kiqKpUrixNb0>WB@Vvi~Sz1gJwr*L`456eXh z-}`4SW+JaYXQSiy^rM*2#2W3WH)NJ%9C(`lmhg1Kc+JZNt!I;|O+Q^)j9IeIBU`*i z)9**<9XJo4wFXL&sL_au!#|Uq8-ECY zTV5vk*Hgz96Cixw)>@;51p=Cq2ahdO|6&p(b5{Mml6kS=zaBvPh2CV|Pa($ufuK=@ z8)pV6S&({E8x0&toGv8fu%|Z3mc}AE$&DouRH8CU>)qZxRbPNVw%nJ|{FLK}LnHtR z4RPH)WIP3b2dUpl$tF!?3EV@QEX+X9;FD}M?+Ssh&%b6DUfC|m?QN(_=~dOJNjIy( zaH?}LJ?>^e`BV6j?QfWi11z_?*7zi9j0LE*!~%4)ep(NS!G_)S7Pe!6k?0A5WdtB^ zVIKV9Pr;Q)S{mq5e|KD8>I$HAIO=ujD`HO9QlQOKW^UJo%g|<(6$;#baU0`EDm9fU z*+?@8De6xfJ7jnfFlB_|B32TmT^M&B+Ao2P=e;H&E1z2lB};qj(=HhrxPi_lhGAb6 zdv&PW=9slCWsSLN9bdNQCg)t)04L4fidHVlSZ1ncBo7XDqYZt;`a5v_5xL~i;llXT z)I`;NA1SUK0#711-FDwRrVC2zt*cODyjwSq<#$D{P(m->Xnn4a23+;DLavkglE4{u zVFEN1!3t8K+6h?Yd7FJae~&Y{%W#ybv$Jr5-7n>vvik5x>cWE zhrZP(>(KQlRw!7z3lV;+SE6|ZKm2pWVHwt%Km^eB6Za72k-B&!VDT1*F60`Kz`Uv? z8hHP-jaaRWs@z*pvAenm{|GLU**`kG4;9|lgpeZoTR@q{BsqL=?lc6I%zKg%WwY!| zAaOx3i@(gJYn3C-MTV;`Id}F1kiQGP{z-W1OOY<%I4$?u43tlZMwG}4L-v#jfP~=w zj$37Z@`ZoF%})V;XL?hu-~Gla)=5%MhmCG*>Q4}U@%V7Y4{dja5Ot(@{rjy>Oj>#O%_4-ecP z2e-?+cISZd+N{X8pcTg3;Ta9JbZI?eH3)!qrdK$Kj+XM7@#;^AQSSEH6+Kghp6ao~ z0L8oOyNa>&jUkW|DMMMLA1N}RW%8b!2-$lp{H$y%-6U^G3$9m9E`v5K#rY5bt{N8^ z2%pd`rJP-}pc|*rU8Y2jQmU3xZfS++0R`#fK>gX>hviKDm4J5t;*dKd=G8pZtKM~W z$sAP=8#?OV*n}u}c|-N@4M6>xn;F^69Nu~JULf^D9xnXLjyq$A5kl=IqULW4t|@Xv zUN~Oh!sr0E;fd7Pv+2~Nkkqb(+MS8^|FYqv922dQ@J3g)YnolFI#m<3k=zrbENB)^ zTP)pCj+xbqOup!VqC0O$2Tm$U!KjV^pdCX5`HR4%z{#m_LsZPv*^dzl(&>Z?4&?7J zrM|5M!@=5VzM_6F(4ER)u8Ybu{aoza^ZX3}O2T&kfdK77uGy(l{k!gV9}*#4I8rG z#%c9>Iz#H{jR?^B-CfKu$;<-XN0r&5oD#!r1lqH1CS6o$Zkw)la<>^l$If!EAy=Bs zwwpA4U%v4248^l%?Zc;0{A6-bcXTpSrXnV9+%2P`QNsnqRiv3Cs>%=jLepO@>2vPuzE8eJ>DOy!C6phB@f@UC>*Y)1riFngBS;iT)I zq*3uCSs#*WGo}Z}CezF}FDnrVppbi!r)TuLXugoCelnw9tjw&M#-=6+I0_Ain_yvZ zGqfbzK2d_90&Sshart$332NN*o$~0WVL-P@`cX~4I=MBtft{l0w$TawLH#CwI{&j@ z8cUoU!{C+T-Kka9gY?}WWDW3LOUbtyc7O;RUyEKve{#-~p>gKU^tK0-W5x(#oo)?{ zABtxNQQUNys%38MB&0vU_3V`<4CNrAj;6sOJ($<-+9IFE>^BpYM3f1nrf(3xKQ@4?d{#Fj;j~z;F|7B=2AhWG2-HU9JS_AiPbj@ zoDI^q3xFC}nIg~*=2R9`E1%ZfZO@349AC=M)o>;L92moFGUHGh)?q6e&)$@sdnF|4O51B=<`m^ zgGcCDq_0Fg_lKy0;ex8ss>0#Iicy)`C-V0aMfxCgf@f!Z@cA{;HP*B^B+3+lM47|j zCRhXlh2cU0U_2{qA#x0WdnzwM2> z!-h(xyBq(0qb4eXMF_b~6D9n>0oH;3;$6u%EMMErb{u546kWPI;?u(K`L8CoF@o*rujs$kuN#wGy8m`!r8{t$Dh|kPpzY|xfDmaZJ|Vey z@Lq(H{#&luzPapC$>Ei)O;ds19C#q}Z5>$y%&MrK5v~0`LBuCdZq36^Fzp7eo*+sp;t& z4^uTma~OB^@zHLUD$*F7p}Sn9id&eOWsIA;Q7CNCzRM~7?ureE-N%dnf{9kkwjCX` zc=CDoEnxF`-C1S4z~65%$qhyEQ3bJ)P5I8YkeXOq$dJz5P+5jTqTz{aOXPicHx4!^ z^hRaxQ8HpY(Piq7)@3?hI<`KR6Qgw3A6XjFQ7jx@8kTi#I+i=OULvtGoqjQ{DR2O~ z*xfY35#ouk2(o6vqOmRWL0ywQHH&8F};ruwyd81!rg7=4kXnJ8U%c?Q|YPXicv03jZ>#(B@WBc4$LN{cEz$%SMwBgm#i>9|HerF)$UzI zwo`~_nSJw?)z-g?s*t#lTK~I9rJH|`E`>?xUa>rN>=SY1+3W!y8d#_KylJ=89@{^i zakRXT6lzrwvvRxeDNcx~22c=}9aAHJJJ4NjiFPwe{LyZ7s{O#EKzvPn!$i0L!)(<& ztm}L<7S~V=<>Y#vD)mJ;-^4SE;96dQfBVoHcYg>o{GLJdKkW_MyRcNAXn8FQ0l;-> zbLl65h@Y&Qt*({tRJs{(tm8m>%eMfE>}vo;^6B0cKV}=S^`Ja2L^wl=N!Li1fSkvS z2@7qrstZ>ZbK$$mugR6R0%T}cP?q1F9)4?YsvzJN9Mk9dvcckQ~bmD=}g`?cEe0=b!D42UTbb&yB!1iSS84DBL z6W0BwhpZBa(m!vdzp_>}DPX{ow^#jfUl+&|;OzPZ#~0sLg&++!%4V zIp+&y$~dDe|DXQr`mv6leyn?~C|HzuD?mZ~!~d4}orNWz9jy8=m=>kF${^+90w8Bd z^}3aRg1jrU@sdFpPd4EqKA zoyFfW$P)18+sYg@Mgk*2y0)Y$`kLFehMX@nQT6dBsNx4$VrKyAaegD^NpPz?~+o&U&57)8iFs3vnuCAybnHk9> zEph-+e!TpXl}QwuGB(V~;viQIMB|$fi7mu|rk=ljWOrsMw0+#Xyew-K;ex0RTe*D& z=iMjcD;E@ZlWGc*UGgc~C@S0t#@6OY**(J6J81^S3%Tvbp%si$DT4q?&}E3^ohDZ5 zz}C9Cg1B~)CB_Gdqs8$_D^t;650>BLBFyZJ(xd~qVAyn-rYnE^WWi)keXi-|n*x3@ z9+s^$X$Hpka@&W&jkJsr(9$b_K@$>1G(oL3GsUURBt*fT%z@&#^tH)}gX@kMdC~H#+Kf4w@wiksX0rD0YR#zwV;fA+RX1HS&4aYS>;Ch#;ZnRz!)5{ zJU%@W7b&4TWW|j(N4U8o=(Qnlu*uUxC4wHBJ(o*csvRgfeKDA*^TPN{ZRxb?hUlvg zcgqM#IiXyyb!-&%pq3CxOA(*;pwU+=kL3xp6@2)ACRv!c`6+*U1VJZn*dxM;5(oG4 z3B*4<^uvdF61+k~!mm1$2=PH>IfL7xmjHtHQzu$EbiAvJbsKy1Kb@nUKqe zvJ<+8U=3cgJbPd(-$AWtHf|YIP_77nEX}|we_Q(@H<6-`jz#wOHM@!uhBA?xBQch% zENw~R8O!6)3VOO+zLiUW^=1<|!f5?Fj{ zQI^!*C%Tz7QkIaqIu*M(wRt8(Pk*Vf<<)8ewgz$*Edi`|wJ&qWRg%uL6)amufFH0O za;xR{kCz%=Vkh_(Y1P~YLxnXyYd2r^9-pKeZY= z3MQl0Ve2ca8@nI66Fn0G2k~#C;#XLORxSwk_B2JaiN+lWgzLeZ`+@X-EF z`I|x=%9Ei&%~;P+PpymvoQ5c+Gll~*>SnWo|POBgUJb4tmNt&G1@o6>(W>cTnNedJCX-gJy6~X z#!pws|MhQ;cay)np}CSgMF%=ntmRdbJF~D@IFy6R;I$Gl zmKI%K9L1oqMs`9ynzM6}G!7X6YduVZS^#B}d8VEWar<-N!L`krZNQ4uLg z?s}o2uHdwksIZhYJ@?Q^J=dh9h={Z#H=U3K8=aJdh=`OVeYcKKx6Cvr*UU6G*UU^; z$E-{(kyKuA)lI>V*Oi<#oYkB+FK@W3xofy9PqTk~x9_l%Dc9)KD9@+}kVV|wBn2T= zjIByOEWT&oCg>(<)D)^1$*H^OujX%-snl;&UgtlQW0Qj}EVyjl-b;s#n266QVJ=gp z%iUF7MDx^=9dyFRU1a5FT$ z;lV*(K3*LG9TYxf2nZZ%7pblqQV7k@$&QPkBhiMD_~|R!xY*lcu+o|s1^0mtM@~mh z`wkcP{sm4v8@L>~?q$XIOByi&hNJn1cZB7ZNTJ3kr~v|@fi|j&>#5Sc%G;f@wX>Va zr0j3XG-T3l^ugo^CV*&LX_+YZk~3!(b8}|qa&qUUvuvuYtShT*U>=^v#vTN?iKhnw z;pxf$p|W7OpmMYl>YN<&NrrcZ)!UGvnQu?S0>R$eD&LeHeXSj%aw593DpEsm_7zzP zIZ65A5*Dvf=1yi}jvyz0)5Lq(ePz+Q^+jg!Bbo85q3PZe$tnj9?*G^$62iB;#(JWPe9r0vgPNw%5DU|g_-P99r;^U5=`C6}fg5&Ru{#s)mzq0fm1-v1l; z5}hg1f_2f(-G9cS`jY9)G(}_tYp<32^pMr8k}iNq7T{~)udJPl4)W3c>k2Kyi_`b% zQ$6u{iM27ktuXlBTVsE?ln>Av3im&FT!-=AKRbr{^&QI^_Pr}sYGuigaKrV z;4-GnEUW~a1*U0UABy4VoPHGRexPe z-O_?o5w&k?;Y>kFL!aQoq?W4qn88J#AmG1X3z38Q?s<7km8JYb_rl4iljf7_PnKKF zTQ=cWk%@!^i>*&LmrHdmb^Vw9@h$PbykzEg92ius`ptcc%DsUJyKYAfHXyJ-=CKG( z&*v3qX7qLr!RHJ1i(ryE5O`j!%} z%1l>o1{{;c`l;QjF#E0_&ihHNaaZ@6`}4e4m&Px0VEfQko;KiDqI$ICih zKh%*;>jAicdyRVo3>Hz{-e;ww+hyNQ#t8w?B38DiAkLhH)CJlrc2z1yCaG`H8?FY< zDGRqJ|HXOYE9#cAt{Os@h_lojPP|_TRiZzWvQUzrGCMt=I$KMT$>?f_@{pw+_?yPZ>Xj1d zE0aZe;d3Lr{IennCaMrsHPowGsL3UF{{5H={vZb729FuIPD@>-o>mb4uu0 z33A7$5Mukt!Cuo#+zr{bRt_%iDOd?+)y%~HL?+QU2lb;3cM7x76XxtVZ@fW39!=g{ zlL%E?B%V03u_%vC6H*fV{1W2`9tm;&UKz1z9!e8(@)JrvzH&sV`{%Yc((^?S7Fcj- zkc$B-))7_?F+lnWDWn}pnG2apA%%o6+#xYEIVr^iX-ownhK%M4iKj_Vu27-{9dLRU zVj6B(=NDE?wSRDS295H8zrG$|+@bggRogrcerP%yLT)tZC1~2K zO&9G)O{MolQF%&J`=`9(!KGGspxh5#PA#Xju6`$N8)a;YM5540gejL*ZOVSy)3x#c0&tm4!FKZuj@#I7d2Tp)Oz%L_UY#B z6Uw#E&owkC&Nhs6m~ug*59WItr>EK!=|#L=3XagHR8ut8=H61|4Qh|R8r2;l&&~SY z&{9oCn>;4)(tGq)Y@eFG+r7Rx&g_ae+P@>i%C9(aI-$rd%SiqD?8P9lW1dI-RGp7F z+uim0Jy=N1kE7}=RIs#ME-ABI7(swXq~??a z|H1H2GX_3qPg71C#*lVnDH#7N@~wNKa>|qu(jI$v-kv{91#?~ktn!lj+toCktZuex ztu%dFV?mX}EFvj0Dbhb9)D(UB$4Z@7HkBI!yLrIHjWjx~qQnSgOQda^-f*^ROZusc zs0j!+d@EeeKB%AeUXaN%aPG5^>e6yWTN!F-h5Fvb-uLafZu-GY`}>OP`|j}Otwn4| zU|WQ4vt;XPVRT7ZQg%tBp+ZX4P(xi27F)-;FlD(?Y5eWW{|7bRF)3;MG~23cSzoHR zkB7}nhXdrZxZzjnCPlC+Q=KB+;xyuwmIQI(r`hU--o>LQr zYj=m3)Y3R>?bQ6jz{NcE{3W4aIOgiAEX_AMxHNtA0cQUD4kg%E+VcPLoj(-iITe5` zlK)&T5c;hkg@%Gbl8h~l960(kCxI0BPZansiBzBC220vrVr$1W1de7i>}wtvCg&&T zEt8f>5OH%b!)T!9jTo_>d0>3DY6(a-VVwytdW|dF_a~K>eXNQ zTc6}r?$p@X-PQvJjDsW)a zpcKlfs=BOtO=!TCOrFMvs>6pRnSM&Y?1;6brHQQM|Hw-Z6#M#yM&(;rM)Js%tfyl` zZp^)<<>(1r>;HJwuy|M@Pm@Sagi~?S?75yTv|3))St*8nUvl%yx(c&8?NEs!e6mp=h@+X1Nn-i>^)Ic%r9(@6XHHqx-fMsEL-CG}VwGI)qBSX1q|+{s zX+caPB(g_T1EKcOsHc$_Eosfk`L*`dk3zru^T^05dufhY@e1933(h&4+V%9~hcG&j z1Kdd#>LMKzASNMpGx2x+xsbI96fDC@1hd)2l*OwxB;Ya0fB1|XtMho!aFnua{}hT9 zp#=j0D11if`<54id9Ni0UqKiEOhQV$42LfcnStzlERwI~C+o(#sR0yzMhq;=$C70A z>eRYL=LSVuR5e5XOCF=7@+b17!vw#%kvbiE{oMC@#i|UIq{mV#?+{Bgh$Ymj`OApf zU>oF#;N8ISp{&hZU6cJh9U=)!*B36Ez|9G}ki+xUvF!V+Par@Q{J*v96PAtkjZUiP zXP-}+UK?zVfZv&WCI-IgwSW;{o;`H5U5isI7t)FloH*cl&Kz)o;CZeX2}!ZNU*P1A zG~igxQbS;eJtDM^0H-5CLWg~G!7Z&p2~kbH3sxqPI}-<7&zXZu<@xLQ@>XB4;cNoO zJu|^gZEk%;qkl8A;XhtZPC*e3%}#Rjz%Fy^`F$d@HV}w42h5dzD4lrfB>m!A0r_%b zLZz!bV#aOer}u+D)b#e=4N8b^^jRy^rFj@!1Y9cRMt!}Qad}sIzx16{dkpKV5v!0F z(OgiuudEAzURr*=d}j%;wIK5q$oA&#>$hxgs7+wxE``%$?HrVIY-^(>5B1)1iu9Z9 zxX4~B;*I(tMGkk{iuu2T%}? zzw|MG2g<#v;7|f$6#$&JZ{FU08q4Sr-!-mK6MrIwU4n;3>6%eC&eGjdp1+sMuAFM6|v^4i*{$F`hBxE zC|zG8GUOji`fi;rj$p63LV^O5okxTcrTVWmP=HPPi!WzQz%}4mG`)((Nt?iN`BPyP zzKxd=WsSCl>yT~V(1pvUIhF_#KKw8@+|)W$-nlAG#E{Fw@tmpEwU+P!lfAg<>&eC#u z&G84!Gs`~6FUR`L2zb+-=bniByN_3Q-nMQu)2*Jp&`KgbAz*XVB+c9yjr24qEkkY@ zls>O2E&w|~#J|^I2+y$2dVhVDola-Qvb46r3NJuA&}99>6J|)zBJfiG ziip;+QdhxFoYq`o`Av2*k21e!9_ZSIcji2&WofKy&OZOhyctz!l?`3f;5_2&;drpzHzjxwyeJHwpNh#f!nm8=}~rk+r#4L?>1sEWsuu7N)3(4QzM zUScmf)l@&!C~~_y6;_SMn5s^giW0&e2s}HJS5kPnB~iwU{$a0)J&5O)Y2-tF#tnbA zR!o*`j(>_(|Agc>*Wy&cPE$=^VlPjqPA;*^up2D)s_MGx5-X|~hMn-LxvKG+5Vd!c z{3#<&#d7-Ml#)eB=H{=Y2op2$gh<6MBMF`V+S;<(!uYF|xp_scsI|Fysge16Gjrp8 z6oQf1sC|-NhrO&KtGZNT55tyq4_Y?KIVc}pVlVeyv`003`xb_q8Z`WZ0It^nKN|2> z^;cafR;Ci~zOjBM#*0S=Z837}B=Gb3-NvrV{)^ih*9nL)02gHtOR5R{s9REbdVX@Z zvFBayiw*4M^#AP`gU~I_p@MjH%HJ#Om3m1f>lS!(z6Q9^4;24v<&GvzSQJhvhUH$O z-a-Skf{$6_toMwjEIT*V?XCv6&ycTQ)RKaXpPije8bWw1%?OnHa0rOy)6K~x_Hz0= z#}Vn*C+}!fzER9XEo5g!FU(9u&t+vt&0#q2C@%-{C$`4azZhJ+#a?y4xUjZNvhY7b z09?E<5Nc)2mAwJSbg@=^H{j-JS&U??P8*?kOs+ys5sbB~-ea#PUFUOp!v1p6eBcjp7}=Hz=b+-&XSL{$`3 zm)Q99qjZJAiS6H|`0QVad}%F+T=V4eyExKA)b%j;XB}pl)W*W+0WbAcUT$G?v3c^w zRv^VKjIm%nI8}qY_5X|9u(LslZ&kKq=(-^Se7o$&8*XUEw?x6W5c*z~Ks+<6{XRQ) z>Qj{maV*^salVHaeXOND=|YHIwXynafHle03!#4}<(W{%6Se&)V6Oq0@aOXZwra>z zQc2C!B}-m1<(D7Ha4*5UkFH*o#*a#kwRn0sDoegiOCF`D4-gl_vx(u8xg+xf!~1a3 zD@A|MTk<|MZ&zjSl*^pd!kFl^qU_A{(x|BPA{P06p=97eGI=HuK)HS~0&Y}PA)bpc zdbU^cuIpV(UC-6&I-;@nD)*_<7;!NV=XD_~1a3kdwcVodgdtci5``br-fHPT?1vUXISUX`AoUXw{I#IgTN z3>R+8MC$0-n%Vr>s@cSYqh~P=gNHjQq zNA_n`brwjJ1e{eQ+tk)GSyR$K z_x$crUG>pHwIwXr*SK?HthH}^tS`VxN;cVA1a*6FXMZ0r~xpz6Df+#nTA3#J48 zt3KEPh)5|a;z!H$qxkiX!jeH}_hfZ(-&9A3j#JXRaD3Mn?rVX8CAP00+zW$6dZnE< z>o?m*yeTn%kSv+Ji9%2CQIbV;=I$azb;85ukXqJ_cgb? z>PvnGX`42lybX#?C3=}B!6jU4p2e2ru!5QmZ2F?Z*i~t0XlPVZd%4@A+M<(-9G@1U znqR(T1I1dZi7w2oZ`^Wb0PFhAqyIW~w~9*?CoDGyXOH&+CIAk{12 z^#6bPpWlJ99qLA(PXJynmn+-=?v%!7DWY+lE4mvfvc#B8cp%8}K$t~2dILgI{z1f< zLRZJ|eRx3mFofTud{_?0yqVQElR6%KKWVWww`Z)RU~nvBC~`S=ZYZaHRQap z40C@>I%45@JUwh_#Q0|i&X}{sP+i4^;hkYo=lO#-Xipxg>Y^jR@CkX^gX+G1^meeHb1+{Te*6sqE{e)+hHk# zOiquUK&jq41}{N8X#1YZEDlLFN)eesAnX+jw~0ei(s3^89z8bn3b4oIISG7JM2o~uI#B=`b>|lHMFF!G`4W0z8{st zTiL{rA)!4}2`8A?=%U$hQbIj{ii5@I3%O)TM^*viM;JLFRWUd>wR)uW-b`h5Ec#l2-EuwkZj@(gv9W^;)*l`^ zQjlNWn-LB}`r)Ku3Yv}(&$c+maut{%(imo_qUmf5XX(*}6(4CV%Sgt9c_}ZIWLov5 z)3pD;Bz?XnkPn<+a5!BER8a6=2%`KaAGkR0Z+;56v9#zf zKkm=u&+kv~&-m_NAblVz+y?wf{Tcj?-mbK2{dGy&bLTST#(|81k%3HsmZ>{N{pdi3 zz`$2kzD6)cWN}7qVxmk|T#`|fn2=eWSF)0sxw0(dpStw=2O8oOWsSxuH|dXSRg9mF z(^ibDp`4l$N4V^L!}M+%jDgbq$CtCIKvXD_$s`tLwmOWj&aU0N+&dV{~^ zm88L71p)>UZ<9G$-G;uW4wJ+T-9_8!AIPgJ7{gU@Mp}W!+FZ=~FgVN*fzSiP5k?3I zTmy(o6;{=8l8@kQ#Kpj zrdS(c2@3y#sa3gWI|7lh;E~R*qW;OcEHx5hhwQ%YwnfH{ElII{uckB0<_N=nKdu$= zV=tj9=eKN6EWb-RZ;yDz2nFVLMc&o^7ZdYeWLUgCsN~%5I>l#w(r{J#l{pY`GZYOT{ulAiLs^GW;gP4Ds zq~FYJM*l6J?QyOZZUjE#69TRco*&G1B&~b61hqL3!ta(L6f{kQJp0B!DuH3gb zN1lQ{(Enll`p z;eKJ__kwGYwh3C1l?ioatRZI4pli@h%pdi7 z=0*-BrLm>^rSacNZh$4el=@XY^U<2w;=hZxSZRCQk&defkc#j&1z|trO^-EiRKCeJ~xnkGST&z1?)@k-mcIjy~>p-{8 zO5yTNQj0{IcYv{Q)u$>!Qx9Ls%%m26oR@Y&q$6VtPPH;UIRK>Q;SKWE@-(LN)JOSA z2FKx^hG+>onDzNL{!Ig63!IHcCdrxH?Zztk`Nj@7guRTK;bwZRiZmXjWZKC!H1x!?6BgqDo6m ztDvcrrK!xUNcowZUO<;CO`n&Mua6=BqXu`BEo4ojrxlwkiZ-Vq{C`JS!9mXR`35a2XKwT8}xlF31}@mbIx-Y^`L4rQkIh4l1U%+taRd!nw8 z!6?BK6cNQ4#3m}6uB#)Lz#+DYl-E#`C;AT{F@-dgpvFN5s6$)_Dx~ZwjP4X~2OT_V zXK9xZ#Q1uPqB|ton9yia>C1D0ry@*V!C{O(kA**oy!-Hh|A}CVftZ?-fmrLF@F!8t zq}Mu+wa&^lR68iPwY8NW=^j7O(4IVgq-*X_4$yIvk2M`hcB#E(3AYSUyvq^XqixJ) zVh62pq%98;^$;~9foZU(Gc{It$p8u91A@R#C&LAbSoANm9!U> zQth;<5&!&0D@Y_lI#tAs8f04*AH#%h9Oq(TOycBrh&D7f4YFnVOe)5~aUyh(g^k!F@1;-rut1{CGUFouFQZlc|j{Cc!I^{*raw z$xjgg{T1VRVldyzCwUL1A9wEXFuF>9i4T<+LMLlAy{hvkmglR9`6v(e?WM~@c@mWo zjX3Ct4o{m=gh1PxBVQXNimz>4D+V^ME6@Uu;AvTRmIEglfFhSfzHd zC-`gJYVa|NCYq&+M92h+Xs5(RMoHFi+jvRY3k6G*2)Qygi1Aty4NS}oHUG;>VY^xw zxGDzCW0}k2xa7iztx98Knavw3xL5#5RNS)vH4Tl;xL`M1s41u!hZ%}`VZ|{BPw7DZ zo&KF(lH0g@c{+r6P}qNEHJOB%v4Ks?$m2HH86dgZH!;rtH!+ zA;pxswW|J0I(lB(&bwLNj~c)1=(VWsYY7=yu)Za4a%bo*IsC#)YC-BiZcm1k1pwvA zE7%M&Bbf#s*KY2vRM3t-rS!122=m0-1D!lL%CO>0RP;Zbrk&P($kIAbO?xHpMZahV z@M4)V_Lj^j{JoP!gu90w(D{&|celZln}Qa+20m>Nl0A5QD15?G4=GtI>HhSoxuZWM zA-v6RwhRqek*vGCyfkk$|3LHk>~3Svr{1@}((BZ}D&rCiV*hE9eX~Zg{7La%ao6(9 zi*rjGa%PWhK*smFpMm-G^t@1=72}`c5>Si-rzO_Kv~@coYG+UyQF<;>mryAks1LF* zYA*N8Ny10ew*YaIISF^k#*wwzid*~VXL)#L=-Q0T#!b3%ld0FO)dhaSTn)l!GgeFe zYw>pu3!=r+`aqWmxFGi|dD3)>$U> z3x8Ic8fsa?L8c6A0iO$GknvXgAU)Cwol@d7Q^XFXGBPk~h(Lj3P-!-}(^Qtxx{D!-GF_&1Ji|g?(L(A?=+} zvyzRH`cL(v8>84(_d*n4g;3Xj(eK#eI6}2bnbcp15YHR=`pg7uP=@`v4!YJMf3BeTvc`47kki0IVCM{fRvN+KfH>BJ>h`ry z(qB8*KM%xf?+kVJ>2ccnGf)#QHJ5cx_0jIU?sVC6ymi&myALuXztuF_rL&mu>?X;j zHjG_7K78};1p&@rcztGd#_i8IRa4(n{SlwP4^ne7eAOR$XoZHw-WwUIp6--9==@l< zQFV!JJ<-&vKhKCKGjdRBZ;jy!uwOMc`?fscHBjQ}Ay~30Jy>u2G7gccrIE@yuQQM1 zvB{MuIpy3E>x5#gs7v0jd>J2K|MU8Dso7m)W8B@sEYxEyu&KK1vA?3=_hv8G6lj_g zF*p+XsW=JaD;!aEmJ?6f!9u2ZO|arsCc;5R>2cGK`ZMSARDO78&-V08R9AFNb;r6a zS!yP#gB|}nsSzp3$>m{zGJd4Khuo802xLm4rG z+!D3SltjQInLqOB6!jHVH&r#SHI*!xR&ghdXy6*=(Yn&&9p>hGgZ+1i6Y~|Qq!vh( zihgGM2MlZ6d4qpfnx39f22%oPw@w3X4?9)DhVD^jJj`W&=L&yb>UEa8rMflAm45LF ztp2qIar&|9vhJz&N&0M!;DiMj4HyfN`Rk&M{U4vRZddmx^R*A8J|g79&DZhSXqOR@ zzDd|*WH4>D>Y(RsP_SzCU>40}4>4C)uC9f_mWHdc?m_lgY8Ox-*prgmNQ4dOd#p1p zEAbPuSaDC%Y5T>>i1{^lP+(B9WgmZ$eD5cXimH|&Y>Akk#y5XGJSB#$4bBfY)oDP$ z6VXh1VX6nuJ>_(K>^KZ;ZXLxCvys{^UgARXmIwiTNK!mZoc8(K&(v=a;|C{no07-# zTMqDgsTcp}4_*S+&JsUTnW}kq2oYrFEG0$-1AmIp)80yuyukkIw*}kb@34ks<l3ZTP=*8o`{}U);P=6@&|88o2wzvAj04=|`+^Iod8yh@N{ss2p*MpzH?TarY zi%s2<2gp5iU(U3bR5 zl6Q(qq>(gd$z`oA1CL*9-N$ULvy`;(V}q~O-XgJ>z|hfC&Jys0Hex?n=SHy@6J6x) z>YfWu|BaBPKl^Y_J&Kq(eNOv8{&;RvS5SmNE+$FC$e?oh60mxn_>sK5xxH#;0<&Nt z)-O!$z80LDOPvi!Pb|`=NYeXk zXjzGVoADg)@b5}L$y29cHzrOcWBk|h)YNxEo#a!jsWDQ*N~&ilZfN$EB%5_Z+E${7 z^egzLwkXINYApU5y+s~Io&>@Uzd}`4h;ro*>sBtlNHXH$(&^;KlY1{WcS8HIQgA|5Z@^@0bkh4Pp9m)$)`;cZ4+&=a zQ-$>%zeZYyK$FtT%t%KMZ-Q-j9M_e>^4{8RbPY`3MH4+`>p7DV-$*hc_&A|I`zCcJ zdJppGydHP4kSjZB??@iD+Ca1s#*kw&!-=tKtLpv5obSl##?c`+9mi2gdbZ z?k_)ou>b7kA<6bXbC}DZhkbY)*M&i0=jLe>Nd+mP)GoVhD7hjJW}Lax(F{lQJ4w!o z#LU00&6--%0D7~;g^}XPI?N432-)2eO@fpoY*T|JJ6HI3rJtKqZh}7-k1j1fii>c` z^Gci^4UA}Xga1VpzNMNsuJqd*UJ~y<*iM^WuDq|yoO+}|9WM}^;+_0d`zZZX)27n$ zZo`nVnI%!v+sTnYa0-s;zuaFudHDG0@%{Tju{_V^LZRultALtrj0|?-z3tpRT^xRt zt9AcyY~K7_g5rDZ7&!)ky2E+ zz*wyoZ&@@u3p)e5f&?QgOj_jCFvfTcDL5)_dT(ZF;a=B5XGLRnlCIWJl8>7U9`76y z-T!fa`PGB1r_Wbc0@}BrTZ5X)*Pz|w)fGYf#OMT`+s6@4nEAqWVX*ReT@!fYb$;fTn#YGh@cveK!^hfgbVK2W*@IsR)clyKG)rrr7! zj5vSoEx&(fddB60#6V*=yI{NvIGM9{RLADKbz(w3ZUO72=()uTu`dpe=hS-hB{12< zZQ>)>ITKyLp??!^XD?_nZZS5;3x#LhQt>x+;AHtf{CKEe92W)5i#i%i8O*P4Co1lp zuDdSC^IcK|!37a8;O3F2+V;3ZAS7Z%jk%$Mzqur8wmqnQ2{DoA@Mwsejh%V2NhD`y zzox}2L+APyq_oF(BwoQ|nbkHl#4ZF)R@q*8rzDXQ<$&<8_A~|}ld1Ci>v#prPl7`1 zY(rUB6ntRL2%gHWI$(Y>ec2?DsVtGYw7r6t=X)$6jK{`_$~}vYSJ_-r)lM90i#IAc z|K;T7%Dp~Px$_oRe3Zqnd*VZ0+g5j$-bqQOG_=>JslZ}WHYJ5MQ86I;_2|*S#_mqp zr8z$5`0BlRp9!u0TdAp2aC0Ra3V;Raj@%1?`C`5S$pGnB4*l^>wCS%FpFWA#^WNge z@damB`re|%8-qc5N)hiG^-W^gAksZalXei0eHtOygO=V-{?C**0u1nW5`&n;9E`IB z%)G?u`V%r3ku|?GD%!M#oy8 zyB@%;Mq30lzgZ2wXb}FnL2tN1?W)4A@ZofqhtobDeo$J5!}VgNL5INxQB|6t+1+~_ zVYjH}3TYNFUoal~tVTx%G>6tfjXG#_wnl9{6hGJG5^U0(l{#qw?E6u<7QPC94QwVR z@6`i>(4k*D|2oh4xj6s{Rq~sdOMoeK`h1r%K~r}?^Rvc{WGr7;?HO8#-KEtt@dB3) zrsmPqt#nVfP-qe>g51MR)dpsw$W^5iSDyyzSu`_kbo*9!1NiKnzu@}K?lq5NgtJ$Dy|9$|v zUnku})Rss`y3eOiwCFbe*H?*HclR|+!G(~kIV;*sK`CB(^SmyQ9b(;^-&hfV1+7~s z8}a?UDf$X49@85x2pvmf&d@LnWf>l3Dk^h2$YK-G@1hu0W?>J0o5}-mZ_!-)Qkx)&ms<5doPI)2m+Ex8s*t<5r z_?H|k09XeII9!Y>01{+XA+ZA+o-M0>N_NvVnmM*gE^R4~#E}5hD9>ckv6*y;s%}O$ zJL7sUa{b4mj_Q9UaT3z`s=pmdE1tfp6gR8-AGWmv)ZG^~;l0JNRm&)s;_g!h=W7*d zrPNlqfq4`#fFTTH1f!V5oSXenyH7F5steHqG#^HP`v}^_qLw~+&OJFza57$da8iqt zVpDo15O!|{2$w#?XQE}>k)u^LYf9-~dqWZR8Ctrb2)rb~#5@$ORggF3)E9FnV!^zc zY3#LTF+O6bS1|62T(J-NJlV!3W?|;#vBjcmyKP`IZ&eVuyL9L7=}I@vY#?f}yX;&! zdHJE0(_HSEAA503bN()9Ps0f8p%%uOf+mVkWWSJwCk(@}8G38lS1z*5p0cB++*rBv zqvj)b12h?AJ2$+)Nk2Y6tZEh`#oOZxx*Ltxy7bV?tt6Yv!+e-3F3M2T*o>ID=A_}4 zrM32OcGkI#r-go){L4I*dO{ZlB`KB`N5VS}h5DMuOR{4<(y! z<-Mo@FAy<;Sd}ObJrnI&5c{+-3a4nOkmjQYlU2g@tgh85^IX9MLdH|NzlY~9X5_EO zumtEmyr`^Yixx(*o&VG&-ZV85^k89Os&mFCfxR|#SNG~@1VzEp6lES*Y z1ZFBZ02@A#M*Hy!r9Lgib!XV8gycuCrx&@;sV=+|S_(tWWw#>XugbToB{`MLNbPVc-QQYgwN6Kyuq^l}R=$|Ep$V57*>I`scFWdc zBTnoW${ERoT5FI=wN{RW>t$m1dbm->!i_QzZZ>djvmDWj1?kpMLuqQBEeGGT?XYmG z5iV~{3bz|}$IdSiYVeW%t|lQ0>#49@nW!D<#u zG@>7SnT0`pUk6{!?AMkVlSzL9k{eJ4= zB31S(YGru?o1*v7#~8d~MYJ*oaaP1u#`L3-!|MsSjt#AWPVHpp-3xdRl|-Vhn7I1;-fVdMr(14D7qH%i1yV_K!Bn|5zIlwufi8wzsDT zx<{iPcH8QG;q5O&?Kds8VoTpotB~c7bVV(is3PTE-%7%;J8pvRe*E3Qo*_Y>AmpI9 zydpkxE>2Btfa1MmSvDlR9`G|oDH<|;yDctYk#zSeU_gQFkG`b-tlrnN|NIaB#Qw(F zcls~ByZ9M@z5wjKCs_cjgnRlregn>tKY;X$nRzI2LW|h{tHx^pmI1&%IR9QQCKCQ6 z{=7|+Sm~nqdh!2{WEGf$8Ckkj|HA3anFe3%JBXfqh( zqWfst(p;uM?ve0e)V5r(AD;=!%@AnP)rmggW*fzZW$6c(j4l@QFhSH&06!NYFTRHB z#muo90?e4wMh}|qA-Ne}vx8~!MkkFaZ8XuCkkV#kS}4_1)EvD>HbFG#Rvpvypx2+;%yg6it)zQ6@*GJe zsKcGeX)YADH#3LV4hG9i>D=2%HSc{~rz`mBRj2Wj*@I%oT`;vpbl7x*^&=fW!;D6? zonx{oW}y7nW#@FCzKkh+K8&YNRW-Sc{{SV!jcg|JL3}Z?g9X4~2?rkChZ6A^vcJlbM*f74Lu`;D) zpVtPUk&&j~x05m>|03Vdka&vgn?WOHymwjK{Sx-Aaj2f|!!iauh*6Z_ zwt#P1@5UiVQ+T)#m>{~u{+=tz-l{zl@@37tO|X*qt+5%Ca19*axvI<&ia{e3v2~h@T2uXuq8|tWWmcGd6sjm7XYKeVd#iW()YY=w+P|%}qP^ zt%S9oxH#mxu)fONb~G&D-x_0d86jjl;zxz?%jFqA9~138>;GS# zhCzwkXZz&&PwlsyED5l-!};9M&`8&wR)uxL-nL~*(_=wrfY^DnI=+J$6ym-|a6!vY z1!T=7L!L>!!lr`e4xq80>99pB7(l^0hB;DWQ6X>f+J_GslhVZR0M|>iN27Bof3zC|_}2|;m(dlO)-k2~{nUg| z*GG^v=i;iUO*%JzWM-^Qq8CGv6xgeqw@(W~;JIoInXWc2E zkG0f4ogHhHt0Gn(^>lnrE-*u;?(C0T0K?-`?LJ z4(5pB0(&xUanxcG5kd6o0b-q8ZqG~;fCa>bTFYj;m z)?e=U4E^5s^NzhfZmZjCdUJ`J2GtkijUB~XBYi2Ky>uCIo5L6egwsvnp8+K7oF{+W zNV`tf$cdstgo3XrIe66`uR{^Bil0Bnq#G1QEzy#-o>f4q50ZTnyBuRo2?LdEOHQHq zAt4Sf?~Mz(V>e@divuAEN+0G|^S^ua-IAnaNT4AIBm9Us2%i@@(Sie%Z1gK(1gcm3 zB?3AJ!bEPc@F3li+_oUSheIR$J48xNRbp#F=JpH(&|r+16Dyj>J-AK2zm}*!m@uuo zB&kbJ7lX;)F==u~$lXsNjZ77AFL+e!OYPDgfVJ#ae0PblY2ueOO}^QTn{kuoUC0R^ z+u<+6D_5N$Sd;Q#jDZ$M*kJDn{>zQ1G1UPnp6ykJ;ML zaRKHX0DcSYPYIl7GZvSIk)#h*Z&rB@AQN6}^SY|eUs6>|lBjkk>C${6)JnR*wl^jR z6mUX8VUNjAkl)LU7$?E3F8i6^y~+jVdA~0J-nb!6cMzi(3kQ;Pz;fOLTS*Bg3w+?^ zg;cAWzC%Y^D@I8JL-_m~&CAhpl-;Txiho(Smf#o-pApAy=3;A+jJ0nyVNN^+^}O$Z#XR(o&QQ$*-CfccHNYFK^S3nJj6Y-Jj8kmGoWn4-J^ZNt zJPn^z>laWhVfTXn#V0HN)0n&Fv(IRezM1auVh@KS0OjN3;yucm*dlWGrkrI^Vsxw_ zH=VRfZj=(>AsJymg&*GH;qG!<)3MN9r)WrxUshSGb^8{r6~O)(z;^eHvU~7zQdHJf z>{Ob8CUIF3?n-*1T%pqqbDs2{1LR;kPAV{k~$DESR^4(ub} z4`sUrl~k1Uar{=#z_HQaYo4t_D(k7P9hB1EcIRmfR)Bp1ke9;B>_(0c?u!Y{gp{kU zWVpA?MxgJua)I7=&v=TaCj#a(nF$2RlLZ_pGHoh~$AL^OZ7zVJNf83h)(DgeJ+`sz zosEeB3L_iUVgyVyiWD!(hh7la=c4H2_uAY5^W+ULTc(oBWZOV|4I^ zjXd7np8}>RpCK+C&B7QvOp-iI{U*zn9(R`s+sWlmkWzNwqdpTg8_uxs0tp*^f28ib z!9`=RJY$&>JuNfCAwycBegrh{AK{|#Kw}apWoLGY6b8n?i=iqF`UT6q;Z-eL9R=oG z@3Eq%r7*xVw3TWG2ne)d79s9}%4f$O zIb8t8HA%=DH5d7;EpyX*RTY#u zx&*Fy$=N;!*z}VIh+qQ==`pYxdIx}J=p5q_x0|}mr$U{0?j&(eY6{ZY6pdC(5G3J(BZK!X3;j%79HvlTe`V0&;qKu+ zBVBn>4o3rg3Us~7d#vmBiCSa!su%*cRjF2T9G=WteOG;R7-rXQ}ZXlzpH>W8Ema9o%qY4m%1OTVUnqW?ymDDK-L zFDTM1k*RiOvfVEesGXhwgaaPI-CG*zmO=seh|5X#z3P4$etS1?H+Q!cKIu9~aky73 zrRqN8TH!8KoF-HJEil?7f+l{Nvz%w;5B!0DGpWZxfl+rIpqmfkrc`xn(j+>fNduH6 zDvd7ckn5pJl9MfCp$~Liu*4nS0ZC7ijtL(s_m1LMmDH^8{^P7%A^-bRnfwW>F#B56PWrrR^%tpX z8CNdX17HWzF#}n~N-QuDVYWa_yjUT|@zNX9^^WN6>v++>0K@LuPZ3DcuI=aSN1tQ+ zX?=Ii$1H0<$jEu~1!Hc=iwrrvsFreY7|=EfR{@u0#7ufrm+3MJwZw^i_9?*7OB_4g zbCn#l@M9>_3nn&bsH|X3{lXdR8 z7Tr8m;z_;IGfog%`uqjh6L=p&*0rXn{7#8A^i}dvRTjBD9Z>sS2`nIqCQVof zRVsZ_!38r|*=_nlqK<512p2X4Pss=%nPw~1hfDRkR8@DZ;4C<=Zwj#iUC*zFn7y*otHOxj=tlp)7nplaNJqj;E0tSsemJ@ zU^$C02Nv2l4n2)SyOwd}sc)yIgpq|nf&D_e*7MZg*feFc>9;k3yzw|tCy$FJ-`Z|o zZjK9^l4XZzzY9EV2#K0iu!swMy(IvL!+Vl0C%X{GiPl36Lk<#Rlee2VhKbItvKeD4 z<%t%U2OV%ZkHp7kaT~QgjhBp_q4`2=Xl&4_F;E&`VcZ4bvjx#blF7_#;hVDbN`8PR zf`K_a9B|Xw0)J?$n_H-s>6X2D-EPgRTmNeJ$SW}Mj6sI9;Z&=}zBDv09MORUWB$Y7 zFYVWTKYf~2ptr9>xP9X<0pi--vir}}yea8-KY`L@@;ZFM>(?2YS7*xfl_~YuJh8bt zGj4)AFaEP|jA|DBXyYCt;pPfkVOz3mruJ{Ee~)Dt9!Huy0LP*EnM*kgu;SpmYuME; zw5HN5Dz)_fc0N2I1np{qZ=W3JlJ6fuvCWo;PP=eC4zZ@Vuqqkbs{JOLQy6qkfw9#nDWj$U~+I zcSla;#O3fERjq5jUP&)-0^MVH1hrT^BA`4##qgplotvTf0*==-(o8RtN4TnS;_W9{ zsqyIh%K1Oy^i}9~Nz1tm7l?HY^lB$M;9I5Y51djD>Y#8&)%*mF=j%tL0k?EEXmG-F zd%yU<(7SKDXbYG&M@@LMk~1iid0@|5Haz>wn!e(m|C%@c-5EMx-*5Vf5?+E4cRGNn zkqMU`F$?C{5+522g-oA-meT4jeHNpz6^hZxu-Hlwjl!(YW}gYvsctAYv7hIeE~h3R zYFXwVn6f;nfjv?K`Soe;v=!gQ_k-Z1hvk67kSqQ|@^;1eg;_7XuM>V8@&+AgTth9K zL0%)d#c(Ix1Ct1_`SY1NYg8^$KK(%cZyhqx4$uKIT$#ORaX>9=<9HH6NkN; zhPEA%$TH;R5dKgmZ*J>)^TLg3I(Hj-_o_@depjE7x5I6s@%EPH?dvltk6%2JYlu$( z<)=qz0D~3>hgoBpO^7*-o!EHnECVG3;e})W>3Eeayb!L1OHJuJ6_Np+|Ku90Oj_;S zCz5i&QKUg{GHRdVL}s+*nA+CzX|(kzY6_Xt52W-<6>Cc%x+Zm?Ji6&J z^bT1mVs+zC@Qx-~unxb1KuVl2es5p_liVM{pexcVO!>@8H2%ySPC?@ok_Dwv$xfS` zh`APCGx$hSj};a7_hcu>F~bn&fz3;?=oV*W*J;q<5uHu}8YuO;YZ3__#HayCd`MFr zn?>>R(41E8>{r#>x6~q`ZzF#eZ{iJ9y-MmIe{H~Ksn6>wv=bTfl*iQ9gg#Hg9fePwpxLon~Qe~~`EN8lJq>AeL0X&f^%j+K%+^M=n$GBbCA6@ z7geTOoP8F6%U$WCI0&?*f_Z$HvEFVGWd)IArD2kvC(#NQ`huJW z=UbO%a~6XJmLNg;{r>Gt>i!|XrTgK*;tWjLXKD#-l^0ji&(<$uk50pCPVr>H*x=Jj zLAPG#)Z&q@=B7jmx}|Uy!+^7c!|{g-W4*_Sp5HkKYnc*u#!6#QS^gjE`f(`L>oxvJ z2@a|CO*UOpRL=wZ)51kyd8&J#a_fy5KbeLxC>Y*2Ma7%l3x=%nJ1d3 zDP3kf)8r^5F8SRHky*8yVobb%xvi<(AXqoh0?OcsYL&##URH?+6amOvkyf1xNWx?4=;zK*L%L_J6)A-1(u7Gxw5?zq? zs?EZv@wxt<(*jdxfUR?e($VJ>7sVP*wuhc$`%zpl%D&-e7*%rin?A|bp6;(L%yYw7 zzGASye5Ao$;w$WlYDXZF$;W7=A42k|6l_}8ZSC|$^h5|K zY(66hWr3-!=5UG^O7V?0){J0d*kX6X=Di~46@a#Nq?`3PO*yPN`zR-S+sUor#=>4# zvr6f|k+zbW#>M4l18D;vdCJoswig#yS8K-y0H51_%?~e@H#g-4Z9{0!giv0rw2&oV zl^sg;N~ve*c-b>aRu|IcI%*b!^e(S@^+YQUSN99bWrj7gv;)tD#R%txj~r_}Rz_Sb z!-(iv?T%?Zz{O!aol+F$)HOJbRO^thLQms@W*ZJQrymC?b%9Dj6CFDlMSMaio>-t9 zSp+!O_@qc>Vsy4pwh}Zd6{zS8zh#|sa3;~S_hZ{nw6Sg5wv&x*dt+x~V`DzCxf|QI zZ992$>-XNex9a{kHFeIMu0B&eQ~mAJpPx*+R`diz028Igz`!%DA>B5U#U$HIjNP6C z49~%bD4XL4M~O4(L|;s4lv8PlxV-nt@kUVOb_*%huHgrgMjB zz{`5cP;KpR{Ht+z=62FNTWR&IuzyZ2ZJAETyi(Z3zl#7&=$D$FJaCxdz(MA{6sekh_xSL}CJp?30fAKeW~kF0G74Vtt>3wJeS#6Cv$SWfCX*K z;-=yA&%lqN2`?lNIyFLBR2vtn!d*8mX7oLBOVugQ>=VhQ%ZYP%4xlGMu7s1=(2rv4 zINiL$!fD}$u7c_A4CBxF$zOx1m03Hc8*`FHyBSZyNq58kOI9h$q=5KAm;!7e!1wL1 zmHA-{2lUE%Ie-kq>C-hHUpfnQud&+nB6bc>yKK@dVb(zxW5Ovh=7)^hh;k+;${UE( zaEB}Y%SeMd1^SbgvXt2wg$>X_r0cH#22mD#d`wpt7`MPY!9)9FFWVeNNFAnl5*S(B zM5ji@OuR;QtFc@+=q%Z`;t}@rGm0)sJbG!-)eY<7(Q%rsf^o& z^yV2}+CXNaEzvJ?oCQ0u9mMWfTQS?U<*b2Y*{}fJ>?BGwf}AOSyX6>B(Oz_H5B%vc z1Z$6)acypi*NI%i(i?GsfjUIRSj51UwMwu(&c|UNsA6(9qx2$lJ%}bjlZ)YUMDxN% z!SbxEZs?5#)}J*(px~yvHES_|5(&w6X}D1Opfv~t9?v0W>R4L-TWF$f*RO&)BM z@+(AM`1nXXihc)`b+3d=ERXzMAQs<~3?+;r+Ak77u%-A?Zxl>fd=aqihyhYMWk5~@ z)@Sk|L(d9aL$Finn3MmE8vc}e5Xx%Sj6BnNNES(igRx3|usTXK|Tk}C~DG2e0GF< zhW;lOOspGuStuKBm}jVFAYgiE1SYpA*->|qZct2J4?%t&FrBB6!o!EqF+UF~+}o80 zw_2PWvlA6B1>22{I{j{KN+#AR2|rmw-6fOabitZHQkVqpDc}04NE`oAm1eE4H0lgO zD-@HPN#SCk^Lhe++(TpQYfjj zY znuc0Zp%jithORSCnmff}P)ML!+b=%T1QpzkCIpL^e#tvo#kv{tH&20;B#mXe#T$1y^i)fglSb1#t898}7o zNva5Xg1w=x=nLNFaM5bP3aMfT(F=eZm|d%h@7~3OkM>^l z=2J-+AF*LsR($4~@JWe3XJ!#pgWgvtFG2_XGFOWESbygpBZj0m!l#cQ97>t_?yc>MEzeDITx+K@)hvia@D$3R2r*J;C){nyQ}lbUY&&v%(mJ?W}9 zEW9l4b}m8>!9#+%BGD}A{6LM4r5WBw3^f#n^1 z$fm{KZ!b3_FK9**+oC_x{mJyNllDmS<%B(yoav`PjO0}@iLq}A^3W)+oafW$J)`;( zvu4C;0|#plJ$*M02-&mhR`|JonMZCHoli%QfR_bphwBz+vx6(Ln?hLGTqdJU#2@1}inOF9o#r1Wkhh^Od1izJ5D~V9WHo5UZVa!q@%ITHNLy*n zL0L05=&v3Mm5&m9u?U;{qOyoD890$*mA5bn6RL~!bQzXE zk5OJgvX+-LEHd*TPsoWJ3%O`=aJkBvNB|~B6O>^iXzRK?oR|TFAKfI<;Xj}qm_atF zVhJ&t%QeonGmh{!VVJ=lZS5Vc);>|)#p3&;#KZ5I+v;j&zjK~DrBCOtYD3T)%QvOX zAanvp;YDK!b`$hid>o;3_>9bQrEeW8Ej$`B^Ri->8HX9c?QUQ}XQ4Nx+xp3S3`3QLz2UkMlHmjv^daWg1M*Wc!#oULIGjI1wuG>DuZ z8>f4hh>U)&@20kb!1h@=y-{24 zXCm4!3Kel`64W;ub2=w$o~p@KxwR|aHEbLzF@Wsp)vALlF$XWF&&=!GfE^93t2Wzm zI0I&bb9h&%f;=x{wWk_JmRig$vMDf3J~+on(z^s@WF#TpwPO8BP8Gi}1*d+dp2z}D z^m_&FvrOpd-u_i{7gRxhxz-F^ybbb;u=xb!?Vzr8A-UC zth*IAXRZ6!a{+-AK1kJx#!R66?71OKDEG5UGD2OoRrtV!U5U=)E7xEDyA?kP0Bi3- zKo$n}SKnLTXV){4?UF^GIW}9p5mV|rfCt-&uGzJKw1+MB-25-znKiq{f>$W)zXOyj zWC9iUd0ythOo3d3tr$%c=aw5Ue<}2fEdICsiHV2L*Kucufv&~_^xFP{rlJnMRz_If z^5yXmwOO(}60#(in7Zys+gN5xXeR5;ACrPcu1&Ibdh?lF^-pO7&8~Z`*K{ONapmi! zn!IWBSnXx4{_8D*bR=d3UK#5g{}huqdkS7JLTa(q1MPO7*l}`()Ob@8r4H)# zq4SmftaPcpM~Y2w+mW5NzW_7N?9FOotUD?-7|ekq_=CI|a?>u%GRl7$y_#NdRmQJ> z_yEPRMyN8*ZkfFUc(#a7qYniXq>TUS9j8)-asK(Wk5YMTt6F1&byE!H0! zv+n@f%yy3xBJDm-i{N-=Q!l%}YxBy3@y;#pg(F$Ieb&v#?LbGXdCX!qbp;;VlyC^ z0ZK?N+Oj`t$W&GY*O)}C($IxmXWM`6#-Bh~gB+j@*EYjo&ek9KsIR?kK6V!h!Q3Vd zgiJZNB^xK+vjbkW9m6RBQ`O2=fRss9OikPe zN<=nVjVrzhJbnc02`-7*H1GElAI$bL!A^ZHFrp*iYml$X^|b5=rxecN74mbXHidFn zi8LHo#WE+9%+%&Pz)@QYpVxa^U5AxalP6B%h@|Yr#D-IUmEy}-u*9|f{mZJ%pA)ItkwOg(U z&IvTH?qb>ck=|j81#3M#2P&&HPW$m#x8RgRI0W=ySDmcyHSktt+UKe-U0!YhJs_mL z&P$uK@g*o!>0KyEY}{Y9*8Dv1E}T`bNxUTR7O6sRvy#vyg3(XVw!&`b3{%e|Cs5H1 z@O&^(Fb3EvYeMlN0Qo43YEkL-qevlx&69Q8Z)Z=(u7f?mbsP#y!%rniQLQPi@I*XC z)n^Y_^taJba|V#sZxbzbwN9|hB((p-!dX)PCpKSbz6=`tuYAUQ@ci!f87{pVZ==yn zDQ7+L-!~Efrn{v5gb<9#riOtEuOG^?q^2)XS|&7@(XPm0Btv2=6;vouk2k!6`+iMu z@-q`WAcR`K0Q+C>{!b#IGM{gBO=cBB@hN#1IAj3k1t31>zSpK%h`*}3W;F^POe&Lg z{fqo13s`6iACA%;4FN~7o_Ht>+K5kWmB^_h%652sJ1^-%Au+x;3u9JfYadX{pv+Z4 z`NIm^`A|A6&_d!W?`c~|2LBi*T?;kc znd-7e7Li;2;X7imj>PG|QYI(%qoK`v49d7jjU%A9+&+2Zq5i6mYrrs1ZQ5?NKFiPJ zVkqxciAyuBqL6kmy@Y+YRXDAgm+rd|6=h70a*C4(1Kumm}m6IziMg}Q=h zN4D7F(EMG$0g zRLng7OXbg+$?F+brXPwGD_a+84cu>0*E!a_{@G0muLc-qF;SO5Y_5@@$jU--qos4C zOWCKagk*KkSB+p7afQTfrGZl5>ba$Z1JRI&u7aBIn>iyD+;JlVxl`uW30wY@xXFgg zXCZq*(#JMtV%2j0^q%o3M%XIBH1oNQi-6jlQD1YuSwM{CJy-HOQ5 z+K2f++pq%#a+lMKIeFR!?jsO3N9QL~&lEx`T4_J4X@8mik;%b4{-zLg*Y_o$Zt|vX zn;cwTZi6q}jZJxYzM)W9R@uOSH{QCitxC4hxtbO&6J%}wsRLdkX#>KP62CnA)bquS zukj~F2tQ)FIA^5=N3Fj8RO#>3SM+%g$WM z#{JTq413*F8U70K7FlqUN`VF7j)c-MX zt{61u2$qZ9RnL=No8*t3OYkDe?G|k`ad^FOWH1Gi>k3Da@i|wUf7e3ugnHv<(4=%`#dZQ z=->#ZGcEm$CU%6D5z7-}m;qAnrrTA1F&lU?{!6;7gpyg{K&Bjps1cdz4Oz66Ct>h3 zQX2@HS<#MNn}(Ofgu7r~VP14DiM&9CAwX$yz)G}jaYTN}E8W(nH;f*|TwUG(2d90ChZpTnBpWWtVJ8SUcJje94h-EFgtd;dcP8)Hn3XSWYUtl~y?iK3-Sng{F_T zKnPV7a{axkS8lxrv}}i!ZDw_*-V7j}X`uqZht$C&njIw)35i;3uf$_ih!U$JLW!Mq z9?&;KWHJ+EF$45%lc7l&R)?PZ%Ro$=CWbUdTKke(tun7rW%Wfn-Ad5ttGM}SmkhfR z@^oaT*_9(GHdxz3>YKI;#}oIg2-|lNQgmIOp!Y3n6083@H&d|fKfxsy9(MxM;hsV` zKqR8dx66p;R24>LGTJx=ERkdkiv3G+^lRJg&E?gBR#p)MfeKOjmfq|>Rfdo)R;P35 z{AHekiq&pXDCEg1=*ybg&1si^O7by!C=;P#kua2o98$HjkFrCP5WsHq#zBw4oDNE3 zVW^IxVdf*4Cy!XpBzK4F6U($oLA;DWJATX)pP|27{Jc)Nc% z9Y8xsTeuw1H7xar%wzOO5!82E2)FoytMsfK)j{(_p9p^ipA!co1n(HeehFW+#LWY`+GLV&9`S0Qj0zjEYIacz(5+! z43p2vuClva81>FrXGsj_1ZhTB6HkfhT`0I&2deyqy*H)CSNdv7F)h}%OlfQ*h0(Gn zR{aUDC0$VBs87DBl4LYXBASOy&#Dg6C&3|vPt$rtQ~_Co%fv^LJY0zEWImvKGiF;u z15-I+XU*hT9TU$xL#SmPg&PpZshM-1u@xhlQ4g|y-AO^~@7xYPi&@if2dD9e&>nD`4A&Co82e z2;S9Ak?w7@MDp-G$W9qx;Gljg?5VcHO)I-sB4foWCXbTcj*PBJG+or25Yj=7zT7om1lPwl~l;LE#xdh^$F zbJ^m}hi`P1WNfbJmpM2oYV*&1v#_@(>@C{}blz_EM2j8}F5UK5=#)943ob^sY71dl zpO_~DTs&}?;*i^@mdtTyI#WOrw8_d1A{F?kXFMLK_#G1H>%Y$%u;WTh02b2n8WP;`KE%4@XIT6(`bfo6GM_(duQnC5rLrtq7>=3{HNRrBvm zzXpWnYIws^yD^Ytacdm2-Tr|7OS*Vv{_iWuSPNK7zMTWD6ZkjvMu7@LK=n@Fulp=N`` zlhYW?JJ4n&z-3sRjWR_%h0%vCP}*rXQfQ4bCg0~28LU8W6#cKx6F5q2(Q5zn z7|a)4=!^N?JYr3B+x#%Bcnbi5>W|KI)-e;_P?C41tC{kWP!EmDDIE)~_iBH<%E|VV zIEnc(|JW}O{)TGs$auWN@-OljKy4P^bhD**DJHJCig9z!KjVI1bq8~Sioy>R0>}^q zZP3#*?vKb{NUL(J(-;mu_NMTre>X=2f3siF%U{-OM`AT~U_0guc84Gjn#naP%} z7NnGqU{+%8XgV&Dqnwr4R7vE)puE}9q%cW`zWU z)vsaoe?mB71RO%A=a%<`a^j2?X;Wh=|46?#QmzUef1vGe-?@m@a=Z$(xc=GtuAYOQ zI=dMvmwq6y3T&p!eiLx+$o8P8mbA3!{%gR{GMd!CLn(dRq*C(NQ+x|)$~Gx%AcvKo z^~X2B_&&9~uW|KugS>c$jkYRXq~;k67=YlfP=<6hkrIO z#GJs1IuGmo_j(p5(&rKnje(U6_wlJ5o|>YR>)hUHrnp!(3#{}kf{tYpO{;h2ArOv7 zI;d!eFID((bzcgN0=IMVpM0mD6XXChA@xXEwV|#E&%+q|);CRk@v^GGuCRQX!F#Lh zH(la6v~C=G71MXs%!{{Kl9$5dVOxZgCy6zEfqo#SC33Wa{<&T86_!u?6YviC@a4$w z*YlTnk^C6E-)gKM17qjW%HP-e*H7){nS)O{)ho_E94?kyKF9s|8iVJ~nz%0sYte9f z|B;gViJZyoNj~dRANi`++u5U!xtkvf4({R6_6={B=D!xTk8ZQZrka?u>&Ug^R?SA! zA3SIiS?uK8Q0*apmF4T{(8UrpMmI-EF7}TVkkmgy=AOMHKi-2Sf7S1;yd1G@H?Rde zeSCC7yn-LUh1w-h6eH_*4GOk=Qb`ArEwvND9*F+jzn^0Nydbc73eK&!2=~rRE9E~C z_G|EO(|Q}*eE-e*gnt#se*%{4vw#k+w6tgCcDU{|!))P~JKiF*!|#QNLZzmY{rM6^ zHt8T4bRjq$V@-@&%K{p5FI0ee^{V=H8`WP+cP<4(lUdSYXi>?5b&sd_wJ&dTkJz8a zsUl3Nxpa1ti~}bXVr9(3#eW`rhFWJ_Iq}(7%NyyNoCfvZ-zpCRxkMI!R33mJYg$?SsnqYj-1xyG~^2@mdy zvifYqN zaAPS18_Y5H$^4$Ecr0&rg_cz{XX*)+k^4qC?%t@cV^m2X8w&k5`^Q8?Hf9$?r_INj zs&PVApU;@q8=F(3%sEm-hVuJ91Gp5WNpdQIIzc(Hrk4tn{m0+G)GyVFZjY~y*6?A= zLMqpqPf1YKl*Ql*1poYWhRcr2o^gq7C>yq{Z@2F)&(t#S6F9(zTxy45YnKGsPE1cB z-|`=rL*RC5idf|MQ>=>vDIglS>!v#tC%#M)OQ`A-Y5KgAu#MD4Knf1Omc)WY>VKHmZ-`J#*WvKJ3+XxDS^dzD@f8 z4BQ8S*UBCR3vF znTU`-ds{|#RoE+Cm%kuCaOv8h`TP_OBE^$^+B=GgD`IZnRK;1YQmGZR8^g9B5+rt1 zX4^Q3FgW|!ET8dLf5#$>bmX`fdtc6?0QHJ7u^gU$V=X<~QNP!SL@|3W&JHkc*USsNz;iKuHCm*qZ7=MZBt@p1v<>?epdmCNDWd%kb+3K z46_{u<4S5f-LnCnA$y}T2ZLrul~vV~%;mpmkpwXQU9M~khByIbiOayM+`x!ZC;kS& z#w1YPlFRxN8dDcT`=N)~GFl&Wk%x_Suti_k-TA95;dK5Dqyip=`>R>867PzM()D=8 z=U}>_ULdkU$PVm8GzQqIWZV^#v|36M1>2G>{`>9;qda|}c-V_4K3agL_Iyo5J~to# z4l1Pciq1Ff}Um%DC`zLFDobPYGl)fEfe91WoD$e)P0@6N^a zwyRqD5(16A!ch)=1(TP`6TwXW#6vxUyQ@>YYQ2AP&bZa)F(gbJf%q;8p0EEFe!j%K zRSzjw=M+ALxqyrjRu$dgHg~vUi!|EL6Y2x^m5>jO(IdKXMf7^4!vskUT>VMzZnFM# zF%&<5lS(aVlH+zKZ5ldEhPJ^VILF9bdb$%DH$|D@S34vaeM~c=NVQ4Hv$Y=rC;Jy> z2;-EARrqgzo%`R*SZkO<;kjDoYbaN!f zeT#%D&WrXC?<8e=KaleXLh3J*2}Bu>hbwks#K7c;TVweLN-I5f59;}^`Xysy0A!ec z7-^V0;_*83gv~OPFR(Mqb;2KisLBV?0?kTdV0&?6w?&}T`yt$>oS-PBr~QXHjxkR9 z_t|tvnkJhco|{fJD7Q+9CcL!WbGFy&09}a%9$yKdhmYpYy-x|YH={y1)%|K`&TF^% zuom#@ci1K+9rWdIPjh7O^<-VJPh{+6cF~6P)q&sIzQ5EiCHHaSi?f{3$2rxzM#a>| zYx+yCaSlg}t{q%)re&d?l^_!7?!|jZ&t8VkA_BKT&*xEo4tey1Ly!hXbq2@Yqz9T&U@CQ5(UxAbK^N062)!e5>pZnlXhqU9~S;qENKP* z&&e-aNsaIMNAXVS1vK(lP^qJT3QAOsph^OmT@*r*vQgjj&mTXrbVuUBbAF;wdGLay zCL0|^VZ9{8B|F!cP6J!-dJ}XNymO1TmYjajiqeawRZ+yp2xZKKB^KXTln1Es8z0Dk z#DXj%UP6ckkzo!se3`T0vRTgp#Va}BD8{t{YK{ATgHtlBdtUGMDFzS`_liZJktzg{ zQO}x=Bs?vCh3AQ7z^Pl$TTK^)|;oqiu5V7TDH!6G7keIz7Xk^^ExgG2Ic

D& zKmG7e67!kl#@t`?2092GluuaI?(wqHGc$CxbhOu&-QklBs;yusvX`9XbS$sFoH+FwvSs*$VNBEt-3}x$RNG$?<{E4Ybo(b3OQlfghskNz z9}K5Z3VQ3758HkG0jW@{RIXI$g7RShkH;@~Tu&=BS_r#d@9~%{hig#_2T@|P9H)w? z=gh}5S>q^Cq)p*cpk@GaSXq4sH<14^6;np5c+t|$J9x&lS&Se9UXJl& z`)tC!CGF^PM{9Gle70PoNpUr~Y%X6Z!}+OG>@qySno#@WZs|(!*Vl)pnmp&Xm-VKQ zd#My=>7WO!yH+kA!}m@QP$?RL){Bk$Qv*y2cO;BUYachhU4q|dA!Mv|yd}&v+!gE% z{DqB_ousX_y~Gbfu*tQR**BQz*PQqTVG6mV8#<{f+pRkMaZ3L)vy(`szQ9`Qf3L->DdXY}1dMc^^Csk2NTKs7&QcmZsc@0=Q*+*}0+ubaVYp z?_|MQ3hbnc(VG!jcF*kMaE)V8EC4oZFthXNL(^I^9lZlOJ$lJAO5=PrN|Oa{fGt+^ z86n<5N4dk4So5{kLjS&dhC18h8m3KH)**}vqTFD5^iMTKEbcl&5* zW^QC_D;06l5fzsu|eN0BcF>w|9d0O=b_CFVJ+E}_9y>Lu<@sRBZRB_KQXt_6*y+3*^M zE`8Gx-~2b)<#e>sMPht9=HdY`yV6x{- z64g$bGMR7NOT#uSC|2C5PQzyT^d!Zjg}qSQ?g6h$P4ccGk1(o5QhVy0CTs#8Vc)~9 zOq7?zT_f$!BRru4nCKiVUdJbNGaH|)2T8r+vx5vQZAuho$o6xH5)jXZGCov~fcRfT z&bKQLJ3z=#;>0N62R2Ai419Sb^WkaElLsFHLI;>$2KQ0{9@j2ZT<&_5+_Qnn+unjA znR%4OQ<~yW{LJ??8#ND;4y+f5FkhH;oGaMu*V%`Yil((-`_{i*wzrFu0@>r@;Q!@9 ztG-5C$|o66q0!cO8N3oR-ZuJgm%HhR9u|9gr72nkgf z`o9%BG~SIbmXx=T6}XWG!96o?82ddt~la{g9g5aRjJlk4d!jyanU_J7pF% z77h|AA4MVw=oD5BKVh$ZqKjco|ES*^`7lni8w`M~OOWG;!0pS{gxy|=mLhl`j&hO$ zyh#a7>{8aWnp$JtTk9*E)-=y}7@o8Aa4GKMcm(?Dkj`*yw&d^BbmmXdiwG6W=0S!H zhPH0Do+Bm19r|tQO1}!sqQwXgXJt)nTYP{voU&oA`&wBCy5wXMu+q{aM~Pnu^`Xm% z>~wKZWVqL`FH-T@4e}yAN80yR(3BfT^Ox^K6v1kT9mt8Me)EpvvO~*=Dzl0TbRG>Y z021OhH){SbYUb?JJhVvyjO_=O!9SzJSr7p`)%p3ee#i#M@JWL}?M@`DqCi*ZE@Tjp F{|Bsk2y6fV literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-600italic.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-600italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c99aabe80340fd88a6aeb5729251e76c9a6f35ec GIT binary patch literal 42120 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 E9}-z&tN;K2 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-700.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..421a1ab25fa88105ab776552d7201205f7899841 GIT binary patch literal 44988 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-700italic.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-700italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..12ce3d20d1ce2288206e8b4f31c20f76452efe37 GIT binary patch literal 40800 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%0DER>;wf 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%0Deo9y(?}8?riQx3p&>dOY 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

33OR1_N*!%ylDDa|3D1;gP8brBkv%FrMeyX$5% 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�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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-italic.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..398b68a0853fbf6368758deb1da49d347e3e7d89 GIT binary patch literal 41076 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

  • ~`;p}3;==ZtNy# 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-regular.woff2 b/docs/nightly/guide/en/fonts/open-sans-v17-all-charsets-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..8383e94c65478622baf43553262e0e31b8725e2b GIT binary patch literal 43236 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⪚aqC6F-jh=?`}zBG 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 + + + + + Getting Started + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +
    +

    This guide assumes you read the Web guide and installed the Dioxus-cli

    +
    +

    Getting Started

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus with Axum, but dioxus-fullstack also integrates with the Warp and Salvo web frameworks.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add dioxus and dioxus-fullstack as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-fullstack --features axum, ssr
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "*"
    +dioxus = { version = "*" }
    +dioxus-fullstack = { version = "*", features = ["axum", "ssr"] }
    +tokio = { version = "*", features = ["full"] }
    +
    +

    Now, set up your Axum app to serve the Dioxus app.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +
    +#[tokio::main]
    +async fn main() {
    +    #[cfg(feature = "ssr")]
    +    {
    +        use dioxus_fullstack::prelude::*;
    +
    +        let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +        axum::Server::bind(&addr)
    +            .serve(
    +                axum::Router::new()
    +                    .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
    +                    .into_make_service(),
    +            )
    +            .await
    +            .unwrap();
    +    }
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, run your app with cargo run and open http://localhost:8080 in your browser. You should see a server-side rendered page with a counter.

    +

    Hydration

    +

    Right now, the page is static. We can't interact with the buttons. To fix this, we can hydrate the page with dioxus-web.

    +

    First, modify your Cargo.toml to include two features, one for the server called ssr, and one for the client called web.

    +
    [dependencies]
    +# Common dependancies
    +dioxus = { version = "*" }
    +dioxus-fullstack = { version = "*" }
    +
    +# Web dependancies
    +dioxus-web = { version = "*", features=["hydrate"], optional = true }
    +
    +# Server dependancies
    +axum = { version = "0.6.12", optional = true }
    +tokio = { version = "1.27.0", features = ["full"], optional = true }
    +
    +[features]
    +default = []
    +ssr = ["axum", "tokio", "dioxus-fullstack/axum"]
    +web = ["dioxus-web"]
    +
    +

    Next, we need to modify our main.rs to use either hydrate on the client or render on the server depending on the active features.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
    +    #[cfg(feature = "ssr")]
    +    {
    +        use dioxus_fullstack::prelude::*;
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see the same page as before, but now you can interact with the buttons!

    +

    Sycronizing props between the server and client

    +

    Let's make the initial count of the counter dynamic based on the current page.

    +

    Modifying the server

    +

    To do this, we must remove the serve_dioxus_application and replace it with a custom implementation of its four key functions:

    +
      +
    • Serve static WASM and JS files with serve_static_assets
    • +
    • Register server functions with register_server_fns (more information on server functions later)
    • +
    • Connect to the hot reload server with connect_hot_reload
    • +
    • A custom route that uses SSRState to server-side render the application
    • +
    +

    Modifying the client

    +

    The only thing we need to change on the client is the props. dioxus-fullstack will automatically serialize the props it uses to server render the app and send them to the client. In the client section of main.rs, we need to add get_root_props_from_document to deserialize the props before we hydrate the app.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +use dioxus_fullstack::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_with_props(
    +        app,
    +        // Get the root props from the document
    +        get_root_props_from_document().unwrap_or_default(),
    +        dioxus_web::Config::new().hydrate(true),
    +    );
    +    #[cfg(feature = "ssr")]
    +    {
    +        use axum::extract::Path;
    +        use axum::extract::State;
    +        use axum::routing::get;
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            // Serve the dist folder with the static javascript and WASM files created by the dixous CLI
    +                            .serve_static_assets("./dist")
    +                            // Register server functions
    +                            .register_server_fns("")
    +                            // Connect to the hot reload server in debug mode
    +                            .connect_hot_reload()
    +                            // Render the application. This will serialize the root props (the intial count) into the HTML
    +                            .route(
    +                                "/",
    +                                get(move | State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            0,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            // Render the application with a different intial count
    +                            .route(
    +                                "/:initial_count",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            .with_state(SSRState::default())
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope<usize>) -> Element {
    +    let mut count = use_state(cx, || *cx.props);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. Navigate to http://localhost:8080/1 and you should see the counter start at 1. Navigate to http://localhost:8080/2 and you should see the counter start at 2.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/fullstack/index.html b/docs/nightly/guide/en/fullstack/index.html new file mode 100644 index 000000000..43d5aae67 --- /dev/null +++ b/docs/nightly/guide/en/fullstack/index.html @@ -0,0 +1,285 @@ + + + + + + Fullstack + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Fullstack development

    +

    So far you have learned about three different approaches to target the web with Dioxus:

    + +

    Summary of Existing Approaches

    +

    Each approach has its tradeoffs:

    +

    Client-side rendering

    +
      +
    • +

      With Client side rendering, you send the entire content of your application to the client, and then the client generates all of the HTML of the page dynamically.

      +
    • +
    • +

      This means that the page will be blank until the JavaScript bundle has loaded and the application has initialized. This can result in slower first render times and makes the page less SEO-friendly.

      +
    • +
    +
    +

    SEO stands for Search Engine Optimization. It refers to the practice of making your website more likely to appear in search engine results. Search engines like Google and Bing use web crawlers to index the content of websites. Most of these crawlers are not able to run JavaScript, so they will not be able to index the content of your page if it is rendered client-side.

    +
    +
      +
    • Client-side rendered applications need to use weakly typed requests to communicate with the server
    • +
    +
    +

    Client-side rendering is a good starting point for most applications. It is well supported and makes it easy to communicate with the client/browser APIs

    +
    +

    Liveview

    +
      +
    • +

      Liveview rendering communicates with the server over a WebSocket connection. It essentially moves all of the work that Client-side rendering does to the server.

      +
    • +
    • +

      This makes it easy to communicate with the server, but more difficult to communicate with the client/browser APIS.

      +
    • +
    • +

      Each interaction also requires a message to be sent to the server and back which can cause issues with latency.

      +
    • +
    • +

      Because Liveview uses a websocket to render, the page will be blank until the WebSocket connection has been established and the first renderer has been sent form the websocket. Just like with client side rendering, this can make the page less SEO-friendly.

      +
    • +
    • +

      Because the page is rendered on the server and the page is sent to the client piece by piece, you never need to send the entire application to the client. The initial load time can be faster than client-side rendering with large applications because Liveview only needs to send a constant small websocket script regardless of the size of the application.

      +
    • +
    +
    +

    Liveview is a good fit for applications that already need to communicate with the server frequently (like real time collaborative apps), but don't need to communicate with as many client/browser APIs

    +
    +

    Server-side rendering

    +
      +
    • Server-side rendering generates all of the HTML of the page on the server before the page is sent to the client. This means that the page will be fully rendered when it is sent to the client. This results in a faster first render time and makes the page more SEO-friendly. However, it only works for static pages.
    • +
    +
    +

    Server-side rendering is not a good fit for purely static sites like a blog

    +
    +

    A New Approach

    +

    Each of these approaches has its tradeoffs. What if we could combine the best parts of each approach?

    +
      +
    • Fast initial render time like SSR
    • +
    • Works well with SEO like SSR
    • +
    • Type safe easy communication with the server like Liveview
    • +
    • Access to the client/browser APIs like Client-side rendering
    • +
    • Fast interactivity like Client-side rendering
    • +
    +

    We can achieve this by rendering the initial page on the server (SSR) and then taking over rendering on the client (Client-side rendering). Taking over rendering on the client is called hydration.

    +

    Finally, we can use server functions to communicate with the server in a type-safe way.

    +

    This approach uses both the dioxus-web and dioxus-ssr crates. To integrate those two packages and axum, warp, or salvo, Dioxus provides the dioxus-fullstack crate.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/fullstack/server_functions.html b/docs/nightly/guide/en/fullstack/server_functions.html new file mode 100644 index 000000000..1fc80efa3 --- /dev/null +++ b/docs/nightly/guide/en/fullstack/server_functions.html @@ -0,0 +1,335 @@ + + + + + + Communicating with the Server + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Communicating with the server

    +

    dixous-server provides server functions that allow you to call an automatically generated API on the server from the client as if it were a local function.

    +

    To make a server function, simply add the #[server(YourUniqueType)] attribute to a function. The function must:

    +
      +
    • Be an async function
    • +
    • Have arguments and a return type that both implement serialize and deserialize (with serde).
    • +
    • Return a Result with an error type of ServerFnError
    • +
    +

    You must call register on the type you passed into the server macro in your main function before starting your server to tell Dioxus about the server function.

    +

    Let's continue building on the app we made in the getting started guide. We will add a server function to our app that allows us to double the count on the server.

    +

    First, add serde as a dependency:

    +
    cargo add serde
    +
    +

    Next, add the server function to your main.rs:

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +use dioxus_fullstack::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_with_props(
    +        app,
    +        // Get the root props from the document
    +        get_root_props_from_document().unwrap_or_default(),
    +        dioxus_web::Config::new().hydrate(true),
    +    );
    +    #[cfg(feature = "ssr")]
    +    {
    +        use axum::extract::Path;
    +        use axum::extract::State;
    +        use axum::routing::get;
    +
    +        // Register the server function before starting the server
    +        DoubleServer::register().unwrap();
    +
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            // Serve the dist folder with the static javascript and WASM files created by the dixous CLI
    +                            .serve_static_assets("./dist")
    +                            // Register server functions
    +                            .register_server_fns("")
    +                            // Connect to the hot reload server in debug mode
    +                            .connect_hot_reload()
    +                            // Render the application. This will serialize the root props (the intial count) into the HTML
    +                            .route(
    +                                "/",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            // Render the application with a different intial count
    +                            .route(
    +                                "/:initial_count",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            .with_state(SSRState::default())
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope<usize>) -> Element {
    +    let mut count = use_state(cx, || *cx.props);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +        button {
    +            onclick: move |_| {
    +                to_owned![count];
    +                async move {
    +                    // Call the server function just like a local async function
    +                    if let Ok(new_count) = double_server(*count.current()).await {
    +                        count.set(new_count);
    +                    }
    +                }
    +            },
    +            "Double"
    +        }
    +    })
    +}
    +
    +#[server(DoubleServer)]
    +async fn double_server(number: usize) -> Result<usize, ServerFnError> {
    +    // Perform some expensive computation or access a database on the server
    +    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    +    let result = number * 2;
    +    println!("server calculated {result}");
    +    Ok(result)
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see a new button that multiplies the count by 2.

    +

    Conclusion

    +

    That's it! You've created a full-stack Dioxus app. You can find more examples of full-stack apps and information about how to integrate with other frameworks and desktop renderers in the dioxus-fullstack examples directory.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/desktop.html b/docs/nightly/guide/en/getting_started/desktop.html new file mode 100644 index 000000000..d91cefcf3 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/desktop.html @@ -0,0 +1,280 @@ + + + + + + Desktop + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Desktop Overview

    +

    Build a standalone native desktop app that looks and feels the same across operating systems.

    +

    Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory.

    +

    Examples:

    + +

    File ExplorerExample

    +

    Support

    +

    The desktop is a powerful target for Dioxus but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are not available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs are accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom web renderer-based DOM renderer with WGPU integrations.

    +

    Dioxus Desktop is built off Tauri. Right now there aren't any Dioxus abstractions over the menubar, handling, etc, so you'll want to leverage Tauri – mostly Wry and Tao) directly.

    +

    Getting started

    +

    Platform-Specific Dependencies

    +

    Dioxus desktop renders through a web view. Depending on your platform, you might need to install some dependancies.

    +

    Windows

    +

    Windows Desktop apps depend on WebView2 – a library that should be installed in all modern Windows distributions. If you have Edge installed, then Dioxus will work fine. If you don't have Webview2, then you can install it through Microsoft. MS provides 3 options:

    +
      +
    1. A tiny "evergreen" bootstrapper that fetches an installer from Microsoft's CDN
    2. +
    3. A tiny installer that fetches Webview2 from Microsoft's CDN
    4. +
    5. A statically linked version of Webview2 in your final binary for offline users
    6. +
    +

    For development purposes, use Option 1.

    +

    Linux

    +

    Webview Linux apps require WebkitGtk. When distributing, this can be part of your dependency tree in your .rpm or .deb. However, likely, your users will already have WebkitGtk.

    +
    sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
    +
    +

    When using Debian/bullseye libappindicator3-dev is no longer available but replaced by libayatana-appindicator3-dev.

    +
    # on Debian/bullseye use:
    +sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
    +
    +

    If you run into issues, make sure you have all the basics installed, as outlined in the Tauri docs.

    +

    MacOS

    +

    Currently – everything for macOS is built right in! However, you might run into an issue if you're using nightly Rust due to some permissions issues in our Tao dependency (which have been resolved but not published).

    +

    Creating a Project

    +

    Create a new crate:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the desktop renderer as dependencies (this will edit your Cargo.toml):

    +
    cargo add dioxus
    +cargo add dioxus-desktop
    +
    +

    Edit your main.rs:

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the dioxus app in a webview
    +    dioxus_desktop::launch(App);
    +}
    +
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/fullstack.html b/docs/nightly/guide/en/getting_started/fullstack.html new file mode 100644 index 000000000..aa24b8a71 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/fullstack.html @@ -0,0 +1,219 @@ + + + + + + Fullstack + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Fullstack

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/hot_reload.html b/docs/nightly/guide/en/getting_started/hot_reload.html new file mode 100644 index 000000000..c083eddcd --- /dev/null +++ b/docs/nightly/guide/en/getting_started/hot_reload.html @@ -0,0 +1,266 @@ + + + + + + Hot Reloading + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Setting Up Hot Reload

    +
      +
    1. Hot reloading allows much faster iteration times inside of rsx calls by interpreting them and streaming the edits.
    2. +
    3. It is useful when changing the styling/layout of a program, but will not help with changing the logic of a program.
    4. +
    5. Currently the cli only implements hot reloading for the web renderer. For TUI, desktop, and LiveView you can use the hot reload macro instead.
    6. +
    +

    Web

    +

    For the web renderer, you can use the dioxus cli to serve your application with hot reloading enabled.

    +

    Setup

    +

    Install dioxus-cli. +Hot reloading is automatically enabled when using the web renderer on debug builds.

    +

    Usage

    +
      +
    1. Run:
    2. +
    +
    dioxus serve --hot-reload
    +
    +
      +
    1. Change some code within a rsx or render macro
    2. +
    3. Open your localhost in a browser
    4. +
    5. Save and watch the style change without recompiling
    6. +
    +

    Desktop/Liveview/TUI/Server

    +

    For desktop, LiveView, and tui, you can place the hot reload macro at the top of your main function to enable hot reloading. +Hot reloading is automatically enabled on debug builds.

    +

    For more information about hot reloading on native platforms and configuration options see the dioxus-hot-reload crate.

    +

    Setup

    +

    Add the following to your main function:

    +
    fn main() {
    +    hot_reload_init!();
    +    // launch your application
    +}
    +
    +

    Usage

    +
      +
    1. Run:
    2. +
    +
    cargo run
    +
    +
      +
    1. Change some code within a rsx or render macro
    2. +
    3. Save and watch the style change without recompiling
    4. +
    +

    Limitations

    +
      +
    1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
    2. +
    3. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
    4. +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/index.html b/docs/nightly/guide/en/getting_started/index.html new file mode 100644 index 000000000..f5f1eb4b8 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/index.html @@ -0,0 +1,243 @@ + + + + + + Getting Started + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Getting Started

    +

    This section will help you set up your Dioxus project!

    +

    Prerequisites

    +

    An Editor

    +

    Dioxus integrates very well with the Rust-Analyzer LSP plugin which will provide appropriate syntax highlighting, code navigation, folding, and more.

    +

    Rust

    +

    Head over to https://rust-lang.org and install the Rust compiler.

    +

    We strongly recommend going through the official Rust book completely. However, we hope that a Dioxus app can serve as a great first Rust project. With Dioxus, you'll learn about:

    +
      +
    • Error handling
    • +
    • Structs, Functions, Enums
    • +
    • Closures
    • +
    • Macros
    • +
    +

    We've put a lot of care into making Dioxus syntax familiar and easy to understand, so you won't need deep knowledge of async, lifetimes, or smart pointers until you start building complex Dioxus apps.

    +

    Setup Guides

    +

    Dioxus supports multiple platforms. Choose the platform you want to target below to get platform-specific setup instructions:

    +
      +
    • Web: runs in the browser through WebAssembly
    • +
    • Server Side Rendering: renders to HTML text on the server
    • +
    • Liveview: runs on the server, renders in the browser using WebSockets
    • +
    • Desktop: runs in a web view on desktop
    • +
    • Mobile: runs in a web view on mobile
    • +
    • Terminal UI: renders text-based graphics in the terminal
    • +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/liveview.html b/docs/nightly/guide/en/getting_started/liveview.html new file mode 100644 index 000000000..89d34f670 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/liveview.html @@ -0,0 +1,308 @@ + + + + + + Liveview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Liveview

    +

    Liveview allows apps to run on the server and render in the browser. It uses WebSockets to communicate between the server and the browser.

    +

    Examples:

    + +

    Support

    +

    Liveview is currently limited in capability when compared to the Web platform. Liveview apps run on the server in a native thread. This means that browser APIs are not available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs are accessible, so streaming, WebSockets, filesystem, etc are all viable APIs.

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus Liveview with Axum.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd app
    +
    +

    Add Dioxus and the liveview renderer with the Axum feature as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-liveview --features axum
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "0.4.5"
    +dioxus = { version = "*" }
    +dioxus-liveview = { version = "*", features = ["axum"] }
    +tokio = { version = "1.15.0", features = ["full"] }
    +
    +

    Now, set up your Axum app to respond on an endpoint.

    +
    #[tokio::main]
    +async fn main() {
    +    let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
    +
    +    let view = dioxus_liveview::LiveViewPool::new();
    +
    +    let app = Router::new()
    +        // The root route contains the glue code to connect to the WebSocket
    +        .route(
    +            "/",
    +            get(move || async move {
    +                Html(format!(
    +                    r#"
    +                <!DOCTYPE html>
    +                <html>
    +                <head> <title>Dioxus LiveView with Axum</title>  </head>
    +                <body> <div id="main"></div> </body>
    +                {glue}
    +                </html>
    +                "#,
    +                    // Create the glue code to connect to the WebSocket on the "/ws" route
    +                    glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws"))
    +                ))
    +            }),
    +        )
    +        // The WebSocket route is what Dioxus uses to communicate with the browser
    +        .route(
    +            "/ws",
    +            get(move |ws: WebSocketUpgrade| async move {
    +                ws.on_upgrade(move |socket| async move {
    +                    // When the WebSocket is upgraded, launch the LiveView with the app component
    +                    _ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
    +                })
    +            }),
    +        );
    +
    +    println!("Listening on http://{addr}");
    +
    +    axum::Server::bind(&addr.to_string().parse().unwrap())
    +        .serve(app.into_make_service())
    +        .await
    +        .unwrap();
    +}
    +
    +

    And then add our app component:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn app(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +

    And that's it!

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/mobile.html b/docs/nightly/guide/en/getting_started/mobile.html new file mode 100644 index 000000000..f9fe2e9ab --- /dev/null +++ b/docs/nightly/guide/en/getting_started/mobile.html @@ -0,0 +1,274 @@ + + + + + + Mobile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Mobile App

    +

    Build a mobile app with Dioxus!

    +

    Example: Todo App

    +

    Support

    +

    Mobile is currently the least-supported renderer target for Dioxus. Mobile apps are rendered with either the platform's WebView or experimentally through WGPU. WebView doesn't support animations, transparency, and native widgets.

    +

    Mobile support is currently best suited for CRUD-style apps, ideally for internal teams who need to develop quickly but don't care much about animations or native widgets.

    +

    This guide is primarily targeted at iOS apps, however, you can follow it while using the android guide in cargo-mobile.

    +

    Getting Set up

    +

    Getting set up with mobile can be quite challenging. The tooling here isn't great (yet) and might take some hacking around to get things working. macOS M1 is broadly unexplored and might not work for you.

    +

    We're going to be using cargo-mobile to build for mobile. First, install it:

    +
    cargo install --git https://github.com/BrainiumLLC/cargo-mobile
    +
    +

    And then initialize your app for the right platform. Use the winit template for now. Right now, there's no "Dioxus" template in cargo-mobile.

    +
    cargo mobile init
    +
    +

    We're going to completely clear out the dependencies it generates for us, swapping out winit with dioxus-mobile.

    +
    
    +[package]
    +name = "dioxus-ios-demo"
    +version = "0.1.0"
    +authors = []
    +edition = "2018"
    +
    +
    +# leave the `lib` declaration
    +[lib]
    +crate-type = ["staticlib", "cdylib", "rlib"]
    +
    +
    +# leave the binary it generates for us
    +[[bin]]
    +name = "dioxus-ios-demo-desktop"
    +path = "gen/bin/desktop.rs"
    +
    +# clear all the dependencies
    +[dependencies]
    +mobile-entry-point = "0.1.0"
    +dioxus = { version = "*"}
    +dioxus-desktop = { version = "*" }
    +simple_logger = "*"
    +
    +

    Edit your lib.rs:

    +
    use dioxus::prelude::*;
    +
    +fn main() {
    +    dioxus_desktop::launch(app);
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    cx.render(rsx!{
    +        div {
    +            "hello world!"
    +        }
    +    })
    +}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/ssr.html b/docs/nightly/guide/en/getting_started/ssr.html new file mode 100644 index 000000000..20b485bd5 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/ssr.html @@ -0,0 +1,313 @@ + + + + + + Server-Side Rendering + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Server-Side Rendering

    +

    For lower-level control over the rendering process, you can use the dioxus-ssr crate directly. This can be useful when integrating with a web framework that dioxus-server does not support, or pre-rendering pages.

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus SSR with Axum.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the ssr renderer as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-ssr
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "0.4.5"
    +dioxus = { version = "*" }
    +dioxus-ssr = { version = "*" }
    +tokio = { version = "1.15.0", features = ["full"] }
    +
    +

    Now, set up your Axum app to respond on an endpoint.

    +
    #![allow(non_snake_case)]
    +use axum::{response::Html, routing::get, Router};
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +#[tokio::main]
    +async fn main() {
    +    let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
    +    println!("listening on http://{}", addr);
    +
    +    axum::Server::bind(&addr)
    +        .serve(
    +            Router::new()
    +                .route("/", get(app_endpoint))
    +                .into_make_service(),
    +        )
    +        .await
    +        .unwrap();
    +}
    +
    +
    +

    And then add our endpoint. We can either render rsx! directly:

    +
    
    +#![allow(unused)]
    +fn main() {
    +async fn app_endpoint() -> Html<String> {
    +    // render the rsx! macro to HTML
    +    Html(dioxus_ssr::render_lazy(rsx! {
    +        div { "hello world!" }
    +    }))
    +}
    +}
    +
    +

    Or we can render VirtualDoms.

    +
    
    +#![allow(unused)]
    +fn main() {
    +async fn second_app_endpoint() -> Html<String> {
    +    // create a component that renders a div with the text "hello world"
    +    fn app(cx: Scope) -> Element {
    +        cx.render(rsx!(div { "hello world" }))
    +    }
    +    // create a VirtualDom with the app component
    +    let mut app = VirtualDom::new(app);
    +    // rebuild the VirtualDom before rendering
    +    let _ = app.rebuild();
    +
    +    // render the VirtualDom to HTML
    +    Html(dioxus_ssr::render(&app))
    +}
    +}
    +
    +

    And then add our app component:

    +
    
    +#![allow(unused)]
    +fn main() {
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +

    And that's it!

    +

    Multithreaded Support

    +

    The Dioxus VirtualDom, sadly, is not currently Send. Internally, we use quite a bit of interior mutability which is not thread-safe. +When working with web frameworks that require Send, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to spawn a VirtualDom on its own thread and communicate with it via channels or create a pool of VirtualDoms. +You might notice that you cannot hold the VirtualDom across an await point. Because Dioxus is currently not ThreadSafe, it must remain on the thread it started. We are working on loosening this requirement.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/tui.html b/docs/nightly/guide/en/getting_started/tui.html new file mode 100644 index 000000000..287ed8ed6 --- /dev/null +++ b/docs/nightly/guide/en/getting_started/tui.html @@ -0,0 +1,300 @@ + + + + + + Terminal UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Terminal UI

    +

    You can build a text-based interface that will run in the terminal using Dioxus.

    +

    Hello World screenshot

    +
    +

    Note: this book was written with HTML-based platforms in mind. You might be able to follow along with TUI, but you'll have to adapt a bit.

    +
    +

    Support

    +

    TUI support is currently quite experimental. But, if you're willing to venture into the realm of the unknown, this guide will get you started.

    +
      +
    • It uses flexbox for the layout
    • +
    • It only supports a subset of the attributes and elements
    • +
    • Regular widgets will not work in the tui render, but the tui renderer has its own widget components that start with a capital letter. See the widgets example
    • +
    • 1px is one character line height. Your regular CSS px does not translate
    • +
    • If your app panics, your terminal is wrecked. This will be fixed eventually
    • +
    +

    Getting Set up

    +

    Start by making a new package and adding Dioxus and the TUI renderer as dependancies.

    +
    cargo new --bin demo
    +cd demo
    +cargo add dioxus
    +cargo add dioxus-tui
    +
    +

    Then, edit your main.rs with the basic template.

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the app in the terminal
    +    dioxus_tui::launch(App);
    +}
    +
    +// create a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    +

    To run our app:

    +
    cargo run
    +
    +

    Press "ctrl-c" to close the app. To switch from "ctrl-c" to just "q" to quit you can launch the app with a configuration to disable the default quit and use the root TuiContext to quit on your own.

    +
    // todo remove deprecated
    +#![allow(non_snake_case, deprecated)]
    +
    +use dioxus::events::{KeyCode, KeyboardEvent};
    +use dioxus::prelude::*;
    +use dioxus_tui::TuiContext;
    +
    +fn main() {
    +    dioxus_tui::launch_cfg(
    +        App,
    +        dioxus_tui::Config::new()
    +            .without_ctrl_c_quit()
    +            // Some older terminals only support 16 colors or ANSI colors
    +            // If your terminal is one of these, change this to BaseColors or ANSI
    +            .with_rendering_mode(dioxus_tui::RenderingMode::Rgb),
    +    );
    +}
    +
    +fn App(cx: Scope) -> Element {
    +    let tui_ctx: TuiContext = cx.consume_context().unwrap();
    +
    +    cx.render(rsx! {
    +        div {
    +            width: "100%",
    +            height: "10px",
    +            background_color: "red",
    +            justify_content: "center",
    +            align_items: "center",
    +            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.key_code {
    +                tui_ctx.quit();
    +            },
    +
    +            "Hello world!"
    +        }
    +    })
    +}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/getting_started/web.html b/docs/nightly/guide/en/getting_started/web.html new file mode 100644 index 000000000..69fd8bbef --- /dev/null +++ b/docs/nightly/guide/en/getting_started/web.html @@ -0,0 +1,274 @@ + + + + + + Web + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Web

    +

    Build single-page applications that run in the browser with Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the dioxus and dioxus-web crates.

    +

    A build of Dioxus for the web will be roughly equivalent to the size of a React build (70kb vs 65kb) but it will load significantly faster because WebAssembly can be compiled as it is streamed.

    +

    Examples:

    + +

    TodoMVC example

    +
    +

    Note: Because of the limitations of Wasm, not every crate will work with your web apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).

    +
    +

    Support

    +

    The Web is the best-supported target platform for Dioxus.

    +
      +
    • Because your app will be compiled to WASM you have access to browser APIs through wasm-bingen.
    • +
    • Dioxus provides hydration to resume apps that are rendered on the server. See the fullstack getting started guide for more information.
    • +
    +

    Tooling

    +

    To develop your Dioxus app for the web, you'll need a tool to build and serve your assets. We recommend using dioxus-cli which includes a build system, Wasm optimization, a dev server, and support hot reloading:

    +
    cargo install dioxus-cli
    +
    +

    Make sure the wasm32-unknown-unknown target for rust is installed:

    +
    rustup target add wasm32-unknown-unknown
    +
    +

    Creating a Project

    +

    Create a new crate:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the web renderer as dependencies (this will edit your Cargo.toml):

    +
    cargo add dioxus
    +cargo add dioxus-web
    +
    +

    Edit your main.rs:

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the web app
    +    dioxus_web::launch(App);
    +}
    +
    +// create a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    +

    And to serve our app:

    +
    dioxus serve
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/highlight.css b/docs/nightly/guide/en/highlight.css new file mode 100644 index 000000000..c23432272 --- /dev/null +++ b/docs/nightly/guide/en/highlight.css @@ -0,0 +1,83 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/docs/nightly/guide/en/highlight.js b/docs/nightly/guide/en/highlight.js new file mode 100644 index 000000000..180385b70 --- /dev/null +++ b/docs/nightly/guide/en/highlight.js @@ -0,0 +1,6 @@ +/* + Highlight.js 10.1.1 (93fd0d73) + License: BSD-3-Clause + Copyright (c) 2006-2020, Ivan Sagalaev +*/ +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
    ":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}());hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}());hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}());hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}());hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}());hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}());hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}());hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}());hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}());hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}());hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("ini",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(...n){return n.map(n=>e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}());hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}());hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}());hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}());hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}());hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}());hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}());hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:">>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}());hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}());hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}());hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}());hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}());hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}());hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); diff --git a/docs/nightly/guide/en/images/compiletimecorrect.png b/docs/nightly/guide/en/images/compiletimecorrect.png new file mode 100644 index 0000000000000000000000000000000000000000..8fab7509fe6321c957b25b77ee2927cd3c24d787 GIT binary patch literal 196054 zcmeEscT`i`^Ka-NA}S&RQWOyc>Ai#^A{~_8i%1PkAoMCtML?w}9i;c(A%G|#E!2cw zL~4N0LVytR;=T8KzxVz0{`uB=>#diyPR>4O&Tg}3W`Aa8zj~~xM0J7T0ssJ@Qc-@W z4FHf>0susPtCIjVu%t| zdGw!W@0%&hf!g;l%t7dRStt-4OzMsFCkx4V%@iMSwt>kAKHF^@30 zl^pO?e0)Ze`+ZT>ji+o97cYM|a!f1f?4J-f32UI9yu;ys%Y`sRefeOe39w!-4=gc! zOX=&$BEQ8;tC|Z~rkq-_m62ix1z!pUsJ^>6c$u~~!!EZc zl8b=J0C}$yNA5BBkDF#Kem*6*`(@`rkk7?0tCy8jDZf9hJKegea)iPycSx z?)TcpV&$}(WkuBWCLJs<7l^-;zDtM~>}At_6UQ{5$ax`d_(yDAbndd$oNRBLMT5I zP;y%Jlj_JZzpeEa^Xjrld8gb#=KhxQVTVQuecC%w{@W4IJC6y^LzIcHDI9zzeWaLm zV^j8$gNT;cTOod9X?`{q>Bz>*UqT3vO(gi$B!BSGO21(ECfiDBSxQn_)N@|6ET>Vb zpL6qv%?6e6RkoK)U+kaW8KD>J3fq&DzAmF+b?{}X5ocMOxlIvA!4ysw4kD&qf<03y zIx8{kCZzolH*TATwdrmo`f=FVwaeOjDf#(b7t&cb*Y&8dC^@Li;BEY z#po2!Hs{W@1i?2~RiB^w<(Eg7LoY`+f3kon(SVK~>oqB`Szy+Jp4i>mvWC=uxo$;P zH8x4Hb>E8^M0|fs92RcY5nH@B%-|?~;{(zv`$Qe_V(V7oEhyo69+JKUU4HlyEqi4 zw#d*(1=r&6A@%D34M(w(Q)IJU{Bo`8!PXUnFEmzcoyx>lqwn0_P`>^?TKNjQAf-`= zE-UvtRIh&S^%DY#H)(Q1x0!l*e#neQoJF)M2_!@^WM3~NlDuG(b5od9;}OTFrghy~ zVzZaLiY3Dgp48JJ8FJ7Z_+#4Bi`!oT`C$SApaCjtYt#G8{T=T75~5_>JzP}`rOcp6 z+y?i@3yALdrH5&uHEv>!kvV(UOhdH3t}UwVqK7SVgmXEdRj{2Yx}3CX2D z`#j*aV#t2;SY=XP{Gm9Bw+_dW$UEg{SD9V~xryb|9J~~IrS_8X73L++mrLIjp7OnV zD9GOQ{)O`19hst+x{r*NrWGVLo7Fe(w6P=Jmi1=*Pv!X_Y))f!)4vkM$PJyQ; zW|2F}W*Oy=y~|zdT*7v2=GOeK0sVoo^LN^=wyCy-`O%@8QTI+Sotg$h&TnEJv0bNP zhyGMINSR6ZNFzwqE_yMhiTF4w3wrXu;lIYfD?DrKGrD_=$a+$+@gjjWfwk1~wVbh+ z_CM^u2=xgS^G}1uUB<1Q?6;iL9Hr+Pr;iJ(UcVAx`Y3Hn;6Z-?IFLNR@<&^xS$(pK zj+&ruk=}~=<`(~$=ABB@H<@_QU8IIl{+0Zbd~S6{4P?raEwAnJKz_2bpp*>^IBV~- z=+?QrzeE;^bBs-C`N)w16<)9n>THF79=+Z7z_x1Wd#+*w`gPWWo_OU5J}SEb_8aH$WQ2euQDv zu7cwO=J4sr3ku%hGE3qf`{MrM(5~68A68MH=iP`JYnphL41IKce0}`Gtsbg=IeqE> zPV`;VJMcT;6PYJMImVwTMg&H9&mzj8Bh?IV?GFkLfNe#bg4{1DcJR@3h?uOL&)3#g^m!;7hm& zjigYZV8396mS>uH;P)vN+xQE2nbJ$el4VaUuixV40eQp7f~4Cc7g7iN=ikn;Ena|K z$e>V&D2Xup#5$rn5}%fpmMEd+5$0~N;`K`5OX7DI3WI9%{o8z!t{(HLXUAvhCs+~( z63m5f5k?VFd6A<54l~#K?~N6B_L|z*2u_TL6oK-OdaZv*U3>ZT)2E_da^`tH&h&%@ zP9z-}odI2YdXnV!qG#B~=mwo_#wLFH>v{V zb@shaq&A2#o2X2wYYsq_h{VIw$_~qCTa%jgoAmW)O(trGT;}${EU;*}MaiX-`G(Gb zuJ2T?q8G%>=dU#v1=W0AeLaY5P_CbyWvHvm?#|A4XMAq5SKl+E(~xCn{%5DJJvfTlhjAtXxzC1j2ce; z<)%HbSH=*RgN5YV&S-RWA6Eud+!R3!RLyzfJAT9SzRND z39eJV(E83-0j%S5uu=BHgfEEaybgKPDitoZ;*CP;&kMC19Hbt&Vss(JIp{8=h0oi= z#Uq8zF1xsEaWbB~0qVh~Cto&IwsoKdO3k-hc(F1|=pnmmyTCb{;2UREOHE@3EVzr< zg9p&#j3K&xI&3hHufwVP8aL9Qtc{`#ZB7T-@z*(r9d4I4= z#SLaYm6_Y%+d_WWTR98O0gy7L#1nN`ND*We5Op*XL#b(my&(kh!su}V;&U3ADnGS*SH4U!M-<_BKd8__@!j%D(bA_*M(QQ!V4NByKzR@lkbp*` zowtxUa%ABo55PFzaVN#`*5{Va>nJn2S!0ps%*U$2=wUwhvu3hQ^43l`wjI##_9`F^ zS#gf{I$qlts@Q610J!jFasV*_1AqiyBEVlV1dM-|9}#c@i2is_2mnMm0EqwkMiYPk z`Fo4Me%AT(PV_z!K!$(1iobla2>xp|#}|_L^3T_Nw^{%A#1jO(ZK&~>Rl(KWhE;@Dn3w;y%mr3f zR%!QVwvyTpAN^Gw{{*~k@9F6#$;apI?ak{g#OvyA$0r~mA;HHl$R{Ysga3lZ!`H>r z%7@3rgYC~o{?pDw8xL!D2RBa#R~Ocw?OHu`1$zQ--~QRr-@iY{Y2)MY-=17N{+bqk zf_y(Id;+}ue1Er%uPXiXt>j||9~&pbhYrqop5gnD5fBm+mHwl`FQor=`Dax<4;yy{ zS7&@pPnrL6{jbXZB>vBefAnee-##V8`2X4EKPZ3Il;-<6^?$J9Pd@+g7SCvz3(|al zFPhASf_JlZ_;tML@K8$^f5%JN&mX}G{*Uv|JHAX1!T7f0^$Y+Y2T*w^uj@mwHAmr- zu#$a_lR|{cU42P$he58sm-pJWXAX*E9uFmCAD4XP(&ovd{otsEn0L%GE-B;57-jxa z=9uRa(N0-Ql|}Nzm{aO@$y-*-r>qndD&$MJf%Bnfcl)2c|F)m*VfJG#WBXtzw?_&p z?W&7r20{zXT0bSeowk@F^5-4`W>gbR*ZO|YY(dX#KneCXjK>-Zkn5_laBHPFL@O_S zGZ)(gI&I3NJ-DX4(6j%`##~01aB~f|T4y>?T&p4>(E+3pbM=#RGk00$BX3lp8zs6?zYLY9mgIibU$xgK43L!&Zp-DCrp_@33M-?)N05aS-`v-rG; zq@FJ&?^|4Hjjq_EXffVVaXN)>-320^(+~Pjffw2# z#;xF@?kT?UTi9H*jq#R2BC;Iq2WrFG@r?G7^@#J%?IJ+nl{2lIGZ{hpB?MLt|Zvd|_&yL$ndF+m>?N6#%bH$IfMr-Ite9-N#F zTx!DZ2AnInE=UAHk+gM(NLf3~(it|>CCJ;w4ZGvHFjp6+K5?iB!)dr@E^!c&vxWfv z{9{sLEgmGR6i81PFDn@Ow!@Nm~foNLX$-N;TOg+Ety-JU8pDF)IW>$7~G-&RuxNQ}|~KJGJ``{~xO z_^Zu%*djK3YbF-1^h$8olR9VQOQI(RkUx6$cit#+b7MB&`5H878aS?eDyZutt`zn7 zl4O{d2!#}H+hmNYwtIz&N(+p5WG&_xfHBy1Smgc{zr`X8$5qAh-3imGtyq=Q`Oyc^ zx}zAiRh|h-p;O5?J>*yeMq@%1O^a1OZXBhTnWkRhX){?y`alC=dmhtgD=D%Qv@Z;p zN5?!??a!4)6BkZ0TyUK$oAijbR@gCSa6B^6V`U&tt?p>9q4r1FgruSVZ7_58M#JEE z?YsF9AhJ$^0k=Fcf1#_A76SOpSIKKw;EO&p=0>Y2aF}H$izWLvpYfV)P^@>+bQn@N zNyLHBH6L0oB|5GkGskIMgFZ3m+}-SUH7l%>P0x!kDP>QoWJ)YFTcb({{$d;)^R*d0 z*5tWf^J8}8SG#jv20108?smA00hLB z|M*+CCv+AMiP3Xx-`gBxn@48o-3wmRr@cmdFJLdjf~L$x>`~KNMunBFmxF=@3~7Z&DpsP&fE@2)OYbU#PY~nR}$6{ zDq|wBF7VF8nlRcTaKI9KmoU^dDIa{@q>QkfDAcxR^HbAwn@>L5Y@J2@eyGanks5^H zE4$XmkRxLQIne45fR%(lQS}xyd|ZRGe27&c+@KH+?6WR!atLU#5J^A`zhoW|2UG75CV@lI-w}T z?&8-3v>@S*S6LyVdYfQevMguh2|D=n;z3WZ@4W1zX(f9s)24sLl)~TZBbT*IUb_U) zSKag|sus#&@iSI@g-}4<>BdnIC=KDEe_Rkb6wx!zi-U zx}kCXZ3Z9Lu(eehcGIEYV8!?hoe45c3d|^8v9YxVK8HUwgDlEW2^6Tx2&!FHN1MFp zAeLiE0l+17#T5&5_*Pw$0LzF zs&*^+q}e)Xdm(fOBrU6Ob|wtL?gpJREOPoTuUPl#<(D2#~@xH&Sfkiu$OWfVbb$jM{jzXaLEUk)(`&H zbg#IyRChi@!}w$b@`yZqSvxiIhiS1@^1WE2vaeBM4n{j1K_EzEPP!a;((~Im_qfoM zZMQ{fS&4x?#;RX^N=`8#HW^~^>~wx%%G;lb%==so)Nnl1i@G=Z+WXW(_(=}NE*bN< z=zCXY?P8$Yr(9~595pBs;fQ-Hb7r4@fsh!z#9ABd0QTH|_w05L1p)s_Dgcs;Su6#Pr%HG z%k^c&|EQ&LS%)HeWAQt}bWW&$MV+OLOxCfkEzkNNOH=z1K;RVpWb88G_7hf(xck0F zA3RHhgYSO+B(o~%1IV`W)YxzhiIOBQ2Ng&f6^ZomGKN4F$!(u63K`sCL3%RZ-3wtvN zo=%c~%-{1O0pVoq^Gtg7fAsVZ`a`)8fGFX*@T%o(^Z=jQ({0p6!nB0;rL^J+>^!nH1umGMc)g5S?@O%1Y0{q;_ zv&QcHero@3Pd(I&rsGi$SU-(Rk0u#K%3pZmzsTaxQU~|2AK_%9uFVmB zeoee}-myK?Y^^HE3KjViYn_Ct;MyV0n4{P}h@QK0=GJU>r0$Z*Tj0O6#VSo$hF^6( z?YLWgJMcNXhbJcb8|$xrwl7T8YMCpENvPdPaDcbNiw_e}H)ejncp-BA?AKp`Wp-iQdPQUr{$ova#=PE|>F# zXl!^Co!Uvl15xdw-_rWM(miy&JWE8kfTLG4YD0goSL8m#x371oR;hm5D%$)^#3iM- zy#DyXsv*_J7+xPG6$87?3w4!>w4HIs)_US4ZwI#EOSVU#G`p8aRPCUEp{lTdX;(N- zj+kh2n#j=ykXjsStt7z$(W|#$6hpp~3I;=ic%Tb8pTZ%1sx{E}JYz#(ke*kwSL#jq z|5(&N(dgeSNKwmjCan~>8^W}F(Nc?PF5B6kT7t+Bx&>$0K1Gwg-a(0=kn(^TQ&;BA zzpe8B)<$SE$@DV-WBQ~8o6_O)H>FOv_SyrtDr>24#N|^)dy+P=fVroz0O#E|)6FsB z(f=~5@H@jtM3Y2}wFi&i8DZ*Lj4-Hxnj=umk&9vWa^md}stq3bTfY}q@(*$|7cE;p z(pPqw30ayEl=>f)47?|1#9v2rLY7@9(QM{_si~NyL0VZ|N>K92Y`U>Pea%c<`_&^$ zTx4)z??6yp`}?1gW?)xi!~7Y=cW}AfvB&EC-xz89@FycjR&SYFr&BL!F9mJ$AONVPW=PDHp^MQgwyx043^=RmGb=cIUG;Aq6^{PN7Ai$}(1&7+ID0=tqsolK8t3a9!#Yvi(wNQ?~tGuEY%hidK@j~DZ4xeBfO9M${qS~fZsW^IPi zdu{vRsLbL(;wK$J`W)i*O*y=7Cn#R2+z0)Zd> z?7F48%^JN+F7y>&qh(i2eO11~t|;kTz6X&kfj2%^^=9IfsnqjTq6BZMr!{BzXP+Lr z!Po+`omrgq^R$dyd7N(jV?X+*bPclq?D4K%SI--5)38VSIc5m`!g1U!|9+1VPL=yXILRp#22M!s+{`F6Ub{>=cpnxMYFE{rSBzeK zqKeoukT=Tq+MX;N)d}jE`n{GA5F0DAx)V5kB)eg)rk%E&Y`U5$#G&`3Go`}nZocI2 z7r{PPu7$#qQNo2+>EG1X48MC%y>j>$vScwH8!5FNykY#kpr!o(>i>7MPQKe2p_hZ` z8CTXjr%My)d3xAaZLfEl`E-Ge-|~mU%AstIYH+*H#$vPK3iF|9-#^jje-u!T>?cM8 zh&2f)+;p=}hRvE@%T*RzF`ZR32}@hqrEfby2WaqHfwJH*gX)9>b=@qToB!~O{}wI# z0z%@-?ZfU!$x;G%0%)+zf|S=hE#FEcCZTIl#=VdBTfVe--B4EA~JFC(~j<%*C;(Z&lg>wU=Cs^Iq&bW)8uc#>V%- z`twPen&Z`Fl)`t6rgukgnw@kw+O1&*VfBd(+(vnRds6X-mM)8lrey^8L#@V;{@y}4 zJ|&<>0vQ_UT+(0FGpmfE_60yxUj-P+*<#_%(sIUA;(7Q`fp9WE3GGn7jeM4pg|hY^ z=Gqn@*kUgS)ZjjcMWM1djOB{?;qHSO2jZ_4;WoE?2#yS737 zqSo)cpfylWo{83~<=Wj!kANC{%$SIdJ^8U`4TYjBIm2sFAb)K#z^hFtgvY4hNtbP1 z6@BH>cJLT*29Ajz`OWUZq`~@>pp*v{K*h9f>Xqe&vt402fAAdG?PxDcb2Y^P5B+rd z8!8x`#|FrdV}(Cd*{Rb$sYOarQR=tnq16E(q5if@jawIDRK@xUKf?(`0rdGl;Y2#L7D^caA5%)Y(KZ{^ZB z;R<|GtHtQPFma}2KEaIsnvuD*)n1_8^T<8}0b}m8R0v`79I0 zsMRqa%$Z|)>rx==Gz($nZ5sz4HVt$zq|$3Z`(W}ZoDlV`n$l3l`g4Di=dKYyHh2fL zeieK`s3_m%PC$LV*)rke?uQC9>lq1mOn*PBjS~8#+T(pma-eb1`}bV_n$GzhcTbr4 z#ClZ!aBas^s2H>@Kl&zK=gTPDNwlpm@;!sUJs350vt8XRI9dHzq9d9L>BUCm%WC_t zmTly&1~;0IRkyDCG8%xoNEV4MumdmW(3>3o^;xdT3Li`>2!3a4({l7UZ>OU;SM z9M;{emnBUQx1L#Tv==yJ#=MmdbhIS<)mq49@lamws9$L@C_y^dVkh)sQ3h(FGDX>A z=APywzWMdr9}(oNWz?(1db2m}{VeUrC>i01tC;(+N2LTaxLCXh4Z6{G;&$yx0ndiC&_KRChoiFvN83%w znD$$f7ft=mvQY~KLP_cQ{>EI^G`}0^AO(J;O(yzEQ9>HSr&U7sJiURsIgo?m<)<^_ z1p`~dH+znzEwm;MPcSd^M-MwHD=0!gNV0s^YZ{W?1?dly1^G%XNnya-Z257~XBeL* z8R^|dziG<<1o2%-Qcm`bfr2A-M`bo!Noov@^s2ZpgE>#=BG`lUcOydm)YlX;I9qztR%b`4GYqY~+p+R)`uwz)PqxB1MWgUy3jq`|;H$;x40L-3e8w{|hBrzyNo4N6J?o_{KgK3b+ZFj7mq3VttK>1h5yLpiV!SP6 zO7yt!yRl6C9LuT6`0gcRg+kRijB;jK@*aETO}|z86;|*rEHt#^JwK7l&npy z-LGp9b{+AjBDYppZ*M6A$foYlXK7#h9qg>7$Hyx~JxVr__PET}(!_=gS6*Rxge6UF zl0?6cZLFxJ1}vW}@)q&OWZTu9o}uIxRNQEg;x>KdkbBr+@Am@XgHIlW20CViU(x0{ znXRiA^NB33J-`te{1Bh^gi3O)UHc76l`ElR4RJ;_6hbZ?P2d8Lt9h%SXX^C>3}w7} zDor&`)e<|ti658QQ-z(+(n2f_T>s$323?2#^_!z~@^GrkdtddlIL_CM+irN?bxp}1 zY}Aa$`G4xR5Lf;NE2_1T|Ew>iCs#2J5L|(Qu{=jPAaeq$o(e>T&xAfEq zzJqf2(il*C))(nqP$7cArj9av7&o2h6DvG7rbEm4yPeSaF&;@!%?mH^&Io(V2X0n) z2zx|g;a<;v+SsuG9hgIWa}HrGWEfZpJ3~cMC)f(y{J(f zt6p-K2Ku78nBD*84F4sg#_e*53zq(GCf)`ORqp=uoj5BT5-cCk^otc&>3i?p;F+mY zR#1OwRK2G{!w*^CvRYNIfoz)gY(c5w)JGGeH;r+^H-8TAue|6ipk#^Zag z^>FU;WdbLD`dGGK{Us)apT3E1>DBlauHtU`>I?}s_Izp`>Ez+KyZ3 z>U<_RROuxjjFl(5*zO;J)6DjlRhqj_S<8Zi>a12w4W_iq0?|A?zM#5GNr}qoO7^GD zLL$z&=uT7Lioua%mI|+iA84U3=a`A_^Ulo$EqDJJX#RWtwThv=B$Wb13^KL}-x+fM z^bikgSH9;bHRw(-i#qFMj_#aD#AZ7kqw1R7&pBeZpHoBfzt)f@Z)*bszlj5_^zRlT zXk$D012?;-`4@=G`mr|YtR3UGTTgqlDN+GIw_0@2K=PE&hgsHUHEbF|uS6%l)aG@@>) zC))_MV}Tu}$%lqbZsNmMGnCEGhaS)pb8ZK7j-O-TV}XuM_4BB_<=xY@YR|8k0|_qX zzf)SKM?YmP>XwTMQ5|WeWI}n=`Sr5$qstS-D?RA18`S*_bgW11_MaZ1q3;LphdvHC zrs3(w-dXHwKTCANk~-`c%Bxl-zfb%+-E0+6k1X>)A+}=@rD|H&rb1*soff9#`&j*F z@?*U1s4N(>gY7=T6@!XB%?<1};uD{23hd^(FdJ;)y$OW=%0E-~|G~M>e+H$8+FXW} z0|^arR||9!Jsj+uQL;l2wZ%8{X74IS1VZJ>Es0v(uKl_v*+YMNNhdpz{PhH4Nua^O zp^5=GSJ3zS8Xw;m&edtUb=-4%L>|zO`ArOH-3Q+W6EXuX^?hd}l<%Hs zbb;uzDQ7ml zuELY0AWavkeow#6EeBvU3O4?IG$PdNKHfo#b>&s~o%bjQ2<^Rax#JNm6ZSg^zbu!< z^m8v?PVFE5okhJY$6Ae_+dEVN`1ez@|Nm3}Kf3C;`Y}Jx(x=u$-VM#glDn^9Zo>12 zEuGjxeXw2_Uu;K26@v!~Z}ZnE+8~Qm+aP<39Ge|8%Lv;h?-8TsRm|A9j#BNjCv2zm z1W!_a0~=CI@Oybv#Eb%V4~yy|%P%n*uF^$Jo~Ik1A4yF=ne_WSIVtmD!%i&b(llZk ze@1G;;#^;<50puPcy~+;R(YxS^%YHVxr6#3MT!^HG)C1)U6w|8WvGcEo}o0|FsLZrK@_386))w30M` zIFHV_t~vI+do8IZy!ot^Vw|~>%n{XAjOrB9;u5O>hgVV%<*%R9vuz@3R{|m^EHj-} z0WjiE9vZBUJ9=MN#SWvzyp5+TT=5AIfzEsiXAS=xb$=A3&)adyb^furf*p*sWVqEL z$bO!0j@&Yg;`z;AR8jIRUQ7KOr!wfH<~wz7PUW{lY^a}V`A|nTuTYHV1~%~_P#QfG z-va8|o12ZRC>$8T8#WBV<^~4anGQ<|eB2dJgrpR<4Fgx6PVkhKcvHOCyuePCnV;%D zBtpWSfH|X_)^>zsAdB*iNg{fH{)073m!4=CLYAn2klGU>L#@RYTp&+?N9wbkbS&*m zQAu@F%y4)WQQ{)A(>Fih`44xRbkU_1-*(}y!<@k-G&JKPl!!Na*(T3WJ`*6rLV_eePq_L+yQ(s`pSk56`i>Z$uIZMBOyRR%NTd1-)7G zR6|@GdSC2uj}tV!oPINLa7Iy>%0#;qQz#;H)|TM zI4Ailiy|xcX^IP%%}t7}e&Y<1m*BZ(D8Z(i%&~i6J_tO*%wy4Pia2VCA6bOMB&~~r z`%Bs<5ShduS(2rV(a^R5f%sAX82>?ShaQWd5`zXz(m`Z4tm52+uuBULvgjkHg6=O5@HSAM-&Slh( zs@?DP>0M(kq12xG)Tzc`BkN=b#y5^Oi;J>@g z=l?6}kSoOR9oc<#`R*AVB?ReQC+htRX64kfMgF1%S{g~GZA-;aTJ33K>{e_vlf@d^ ze3=T@+S9s17?m9gzhA~#@%X_fvBlDJ&nD&|o3@5(QWp}JG3~~AvRD-snFBQ*bg9S8 zL}`^@s&~x9CXJ-&ZJT_*Fj!zeu5b;0y%-rBXdNvrHB;@_oaDorXb)HJ8%bn&Ye&^YAwNR#)Ci8rqs*`b;c?I-jZe+WG zI=h(?!cMkzz>faa1)&3x&Vj6Y$mYe&GP>&Dn6Yppe7bQU>q=31Xy^y6g}#HjvqAP# zw+8U$Cn)ValNy%M{4_6V>nONazqEV7vw#<2O|4wEWX74D((tB@h(kt1h~2_0$NI>P zuc_U3Ai3PB$EmM7{OwUnTE!{hvLW53<<)MC? z5@is?FlyWGz0$|zcAc9-!RWSjLuke9vJL^^{phN!e3uSh-WKHvQ0fSxUS zvg)&JXVdJ=Amrtp>}T6C-I8SW;7}symY-*mi{JXpCP=no+4y{b@{}Jc5#NL~C`d(l zVx)$S!;6y8(bykVgZ*{86$tR>*{;cQEO@YVgJH{$bFz6Yb6g6uEjS+}DjlLRY~wvN z;R7F~XmO`QOa$*de>P1)&*r(jbN*R|W}d~h!=;Iv=0Tl|!lFU?`7KV?-8;Pa%rZ<617~{S*R~}Tyq28Y zp0t-d*tyWE1E&(G2`uZsZaB|3v5MWLgkn1NU{{U(73^JQ=bTMU_K&&*z521mljpHP zdml7lw{7*04CjKCV%cuGw${1oZT%+Nk&TCQkzDYUJ|n`4ZgBrq+X=nOY*cD;Hf3;= zp>IYMQ^e(BBije07YC(pSrK7&#L7eDGcXJX;3Lc+d}{l^$D7BZ6iscwJrp>^e2?SO zgvNqr5bXlZ)w`F*vFL!VC*6>Y4#*%2Xf6pT>BDKkK?t-jhV1!HQ`RmWISowC*)Ux0 zxSI;_D;Em!isQq6-e|Ud9hd})aJMin4VgJ>#uSs&wsf?3?u$?mm0Y zy6FE6=YI4nat*b`Cs&+F$FEn6UiA^Fb;c+(%?qeqcIx#A5`YZ3!%j8Uy*|x05z9Nd z(;4jAs~WhDcF6|!h#X9qnUH522NL8J@FjIX=S+!$NH6Z2u3RP67{kJ;oaJ~Rhy>fz zIy1ZDifu>7B3_A4VD2Q)$)hzv(xKOFcVnnY=4=>$YRIXAaz%`HK-gedS2^YJB7g8* zwM=PrZ}ZIvBx*{>b?oAS+kMRb#kkZJdQHO}e+8n+aCw~pEQ1x7C}@312(<3^BG}br z$BV&ryDW_7S8$zm4{tj)MnF6^z)%A$Q?YopPH>=qlUE~bue3e9>9aO2@J zbt2}LT7GUwI7y?l58l#UWU!V}OI-+xG^ag5qQzh*}Il?_N z;HgLfMP#+Xc-HxCc<1a9TF$lB^n6WGFjT*Q=q1FZ0X;)D2uGu%Oe zd2=RO=_Y$-vZg`C_HYd`r5b_=~ugO_)KO6EopbG(njN9C?~Y1mQ}xe#4;*<81TbaT zL}paX2Jal2z32>YiyOb--*%UFW`UnNcAxTNn;BK*O1;BRqwr=w@~iFLos4Nzx7|iF zOOQzzO?rV>+ksNsA)nppO;Go)P|uCrz<#=olR8+zo8*=SyINkxjO@*L+q2+>XY&NB zD@{taGgnt7L1H*Rn2U(h-DkK6wrA*O;%e$+^H(wk9?Z@1$+53x$391y>zl_E(Dq|W zGIpm-!hfSZtXp`gvEqo4i%3ci*@49co>nEbVjxFM=pc>x!157Uo>1d$0Bpc+E8g0+ zIu@*-iiR);*v1sR>Rd=GK}1fnfNTg`(F?;R$kexjw=~u)q!q`yQx-?}s!3lbbyVir zb)-Pv2x8M$H<49?O@0njezYHTt7aq=M7B@wZ6e6;wP6QapCzrDrY+t0x)irC;?b`` z?(m>vvYZG!SL(_+6Am4+iC*}Hqt!kLnp(_` zCp9*!cAh%6(iMib;nioo*IHFXmY)c%Rq zrUG1jxx3vUcc3C@=6>qp4(_?L&q7f9Q}EH-Du(&76G)BsEBZ<=l3$}smnrZrn{r`P z+aPcAR?7nXV@>W0Z0g}rwdqP?c-0lP4o1$9x`x9#32M%sWCh2$1Fg+;Y%J%{z}tZl z?2enL{fE-fPu_Q*;jL46r?;#nZn~*XefTvfz0iZS6uY^8anQ#y31l{7{FRAp-`!&P zbMUH^R*F%L$3Usk+I{u4Y{&S#WK|#1VHv{$Ru#j zA=FFN7e$;)ciP!{1QRYTMMzk}dA`YylZj+UfT#4=ZqEjF9GN(Ve#MyfzQER&@3x1WuDZ;|Uk6!BcpIGG8@Ro;-4vD(e_!H@Iv_bzZ^fITwCkiO6@A z;3*}RnH83hbniC@#e{Y76U^2&jgtF9a@BKCYt7Nesm>^9=|hZp(5>%tu925K8BeIN zyM3VgsGWQGQ7J*W^xNG2%-uO>Mf=8pWWJh@M|vWHYYw{DIbvX=vNY6V?vL3 z@BvE*k}v090+!@I1D2OF^M8eXKSd=g@MpjhiRoYeRr`L@Szq8y|CKKV4!>fmpTn_V zz>~Kz=Ys!o`0HgBez}SF92kBP%RjoCZorck; z*ru!uW^c)|*}TjW_&IaRZktcw6X?odproB+qRR?VdMMWrw95msU!wb=}2xn^u9FbdU_?2_Cp7%!C8s zP^S|!ABcVX$osjO-GfPryWw+YT2*eD=P-pH)cDuD4995dyv+rv<-;i1ZjeS`jSnzy z^6#Y2e@BqDiI?(kP5Pedfa#myUn&aIJA+CvjO$wjC)pA4x3n+<|l z!^?V#e6`SK+F9Q$o)0phK#mK@n%b?sq|B<5NgVC^>Vaus@n${(R}$@xJ-r?P53fY} zC`_u>-0TcV{jNvfDmMw8-Pg@#W^mAoUPkRK13eF_E5+m^e&Y^@5gTg(7(Wyb$aHyn zxtD%Z{{(g$rRL?vm&(OW=%l}=Ma*4oSWGH-tqw4;P1(%taZw+0rLKQi^1H*?ka(t+rVD%5)7tsw!Y60BP>{i^*h^r%!?O>O|5w`rrs+oBbjDuRGx9M@P>h!g!9Kn6Q3+7k*wZX-@0lC zx!|RlK^uhyc|?ZDfhR>i){)i7VobIPis~qdV^Dp3WC&^@zFATMM4yx}3)lGY)j_{& z410LzA?9OtgwB2w&^Ok{pWAZMhKbvt1$A(<71i3bJ?!_sCYHcxJGev@?Wmg`C#O@Q zzO{??1?Lf(Y@RSk4vUc0K8q7|nOU&1?YvZ(2hzyQaMA05eusKsSs# zG@6^aeB7pi^(FebV7;#nm}^Efx_ZGy+_8y>B^MxAk9wi*8F#yMmK0_CxXIw*V)@53 z9R^^@gSIGrE{VO`r?h38`!|@lt2gAzHB5q;89iYxr=?srYr6NWz7z1e8kl zKWa!NdBK`9$;`t%cRg%2o%c_*STuAez$>SxHXH-mRJJj*?;i&8bEsfq^+BTt?3;F+ znlqXu_6o1(lbI{VuCE+sW{j^>YL%Qu`(T$>eexE}vY*2<9yjw$CrH>pB3TNwEYwDd zF+}K2?Zgy@4%?6QN){&NZ+_@>cgzm$i!)6n6@t+mg_ad{> z!<BttZJ0$pZctb8i{eW|y@MV?|rE6qiDQ;w|o4pt!piw^Ce#Lkq=<7719a8qnO#~|YBxBr+OfnMeDqM_C|hPv2Y zE=JdY0B5I*eu=d#DbKJ^yu-uHo-o8=$RPlzD6-z_3`0Ey_&H?e9)fTB~ zPX7#7Mka{Gf@ zfSZGv;HGzV*zxP`-TY1@Bz58feRVIfJ1&&3DiG0wOS5c9I~a{1^qWw+V^e zlw+o6J>?lYXBWM^PihGr8AqKXS6*=c7z*Ha^CB4;^CmL$niVH`hD#3~!Yk*`-6A%} zW(U`*fA{)n^_4ufloKe90 zAjRFvyG#+0QaLhyF$G3mBLjFCc0@3=9w@%6wMtBSSFH!oEL+0xXer4M8;ybfcIb46 z<)5>$lgIC-#Vq={{3wdPFm`C#tkpVNBm(yYGbI7Hj8WDhd2W}ZW1->_9Medimkasi ziCf2RZRbyk<=~A~+766|WbMs7rbLuC?fMA9#rh^#RrHthf@~#A z?ei}6ot7S^(aA98NOQas2aoYd>+j(m^+H|$p?HG$ueSNcWsO`~o%dZtum;5(Pnyzy zg}b<~P5%Ke)I5FM5T1%q;1LR9ADRklLs7+i#S;X6JDJ|CVO4yk14lEBzp|eH#>xUV z?S_l4&b4ovCfWBr-#MIJcnzv;SW!*2`(U4$VnXAM4stSzDdo?oyuaJdQRrwj;x;ms zOEvw%qK`VKV(saaZsF+^?Sl`68{>5g0kbQ1`WXbep=TNAN;FD=_xoor5W2F*9XkV? zG&`X~nrFBBJ{9;4ZSa!)v>*hGOiSU6sfo~7C+lQc&OCxSUH*c@=+KX&ntft zy;q9*b(z>_Og~iK0kdUeN8exzTT@ihfeQJsV%27kChiU}vN}B8J}^A)F}luMtJeQh zza&en>2Cer&dG1KQrWokqHGB6+P|_}?_&)sy9lfATv1eY*zX$KYAR?cdtBm|?{8xo z(HVMHMWlp8alFNvWCG?LqtUIro~r5fTV2#hz)Eb5;8cRWxA+eV)DqL2QM7 z6&{w_b&3>T)V8xjc-O1zYSi7t2$+K7J^rqL6RMuWt}Tt`K(XEJDOm=r{ndTh?V|;J zo}a9a{nw3J^&ma(?QM(npr`+f&cqw+fb=ca>nn^ZD1O}|5}#g^Jv5zHk?OhULNQv>-(C8IqV^Wlv*F_bqZ(xnw)T#8&-Ig3_9`m{xE`C(2$1l(Fe-n zF>6n4e`RNLbo*V|kfgT>5B)JsKfg;{6qHM(`c`ya2xro_Iq;hF7zx@L;Jmnk;USM~ zGtk1}gzyiK4ObX%Wf`*``SBaeG;nXf_gc~Quu9V48nH8v ze@4{iDx$pZn-a~s4a5A3c$7{%ig;+g`C)`9P~D=Ai{M*=g=%i{h9<3ze&R*9+J(yf zHvn%{U8nOvq||0E7pVO5^;9=x%isPSkH(NA=xR8N_W|T!?U0Xf;-UWbM>pt??F@d< zSVd}JuS9mB83C%kI#`+5W_H}}m2RSZe*br`AOWE*4MH_99V+|64P41gd}ve_Difgk zDGL9KB0q(Ko`GrF?I?dg>6DEY=)_8Uu;cV+0-!^edhOs2sG3o^7I=J*-LW^km-qSh zu9C=OjUA5KTyFXV$D>&^MM9hq;@gd*wW|BLESOA&>s1 zEyvh3AEc_%L#b)(QZT#+>qR8gTOy2;b2vjxD2ot!-#`LL#6Xh$e>XY*d_?;uxPb=J z=P?Vx8BM*b)(meIg9dj`#=l#T&QS$gjw9(q#H+}iLT}U$0=i{tm%2#)N zo9NO_Hc@dN^(`^rc|>`AXTXUl$>D1w=zM9Gez_z~_ZH1*i}0s~`J_s75Defp^0F59 z=oMUWH5+=Sw+L$=tg$f;fkZ#WS>MB)SNUNc7y12Ha{@ayHV3TwgFZ!%UjumyV$4_B zHIJ`kVimv7+Pw9v@XPX*R`}{2qfg|Ss!zn%`||0NQ&GgSjdA?z9wFw4zokXYFxv43 zRK2HD4|u10PL2Rt1WfZyQdM0C*A>tiOLP%$kmo>d6n~67X<@MeJ!Q**`||#B0eMxo zam(%}eb*J<$6r(sbRW!AA2n$Gwxs?ZF58pXHMT*2?O#c*zNCZpGPV!SJ&=SZEx%d6fB;KZ^!NiOsmtY*sHuHOb_wfKVES_Pk| zzF0Ivm+lMmBY8W=CTA*VZRRrDb3gyB58wTb0%i?5daomW%OH5%-=)l|rDj5OzcM#G zJgdHvR+*h)g@NleZiP|)@t<3~t^Ogt(XI6IYSF&#vq4BEtJf_w>Fnz#V?g+Y(pDf> zoozb5W&K0WQdsS175IFL+ThaTj_4;FrzTu^jLL&u{SQrigm6%D?56eZNJjfZE&R>U zWngL96IZQGHqDy2;_Ra7fwzKA#(c-@thiq-oK+?rp=&>sozOSnp;NEddA;jp0O*&o zTUDG`>GN-}PikF{j}Uyd7Bg!YcR9|^>d#?&KiY&%1*n7QAG`A#1MEn^cK+-!91{=e zu1@VUH(CF-HsupA|NYD}C-`QBL_u8Evsn>U>Jm|IGx`&Qxe%eFRkHEc`KQOx$~Dn8 zk>sC3+A}V0Q;ak#3_?+~uXPT7xp@}$7>erK)k?&LU$tFIW8ckcsxGc#GO&Rwl>j># z<<=cifk&nES@XHVE6PwN=f2XmrKS6xslg7gl10aQjMasyu$n1mF z{>q?8=aEgPIC1RlK|^ATV_)hy2R%jQm0PRBvcs_i$31fSa{m1k&%;Kb6U%!9`CYG- z$mo05IX3*;2-ej4faEJkeEaD3tO6s-W3p(~YpRbw&x%4D+_frHc%Pkq<$&ctY10NBIm*34rna=Me7|!{*v>W2`~Ci7 zi?6b33DxE;ukq}$rnT|Bvmi7%`M-L4!qYQ*4{d@;!4p?(;N>F4)a6`Pd}%KJ-{tS) zmj5l{_20olr%;XY1RLgR%yy?t7}xN+dY_n)%nCi;K(&R842%!F{Y3Epk^Yby+`)T@ z8Cebwk0UL4TuI5YfKr#^pJb)n!_T$hfd?BXn;_@L@eE>RT5i9jRQ4Vu^u#EA_q!UaF>5?ymeLKVJi$)FbO5HE zjkr5yS0&!d{Q)EELaX}IP$>4dU1*#6Ka{}_9qiOici{`L30dtH8_0sM{dGz3i|5W| zbvvsxCD&SO>5GdK66X8lL@6f5a(WA*V%mmxSqIYQ>{Fu9%oCdXHr1|puTk4mH|rvY z(f32c){0g$z`7G>=G!}V7s>7+Zt{yb3vxi#fx~r5-ZR6=tI?Mk=ufq37Ng*IHZ6OF zCdNjJRGAar7hlQ=K-QBbSd6Bw7>U+8NAQty13%p6jah3d=&GPixplj%ktS0*hV~7j z4x>N}1%MVt?u%Xx83em_1uBUT6XJB>Vb;1&x1{+PB(5+|uDSaK0!(jCvcQFnXj$^) z7Tt%60Va8e<%u2P!zNbp2wT~d{y`u~Q+cZd9AwQt*J|X@l}=WBBDNyU&*_%!G^e__ ziA~kED9qYiIBR}|UIn}w-_&}@<&*n`-mU$&Rw_t>=ouXegs*zzrE@1rWPCcC#YOZxq-Hg&AVgxrLX6ParK zr-U;_nl0C=#?G#~PX67QdKDuNFVN$=o2CPACQ&cb^kZYggBl2itd8BRrrehAvCel6 z(Y51oAP%<2iJ8rQi^u%@pikTJ_`GrK|D0m;Pj{U}69S$8#jXIL(tt1p0WDGHWW#`9 z;=^sZ?}+mbzEBUm+>x7fpN(qqTYQ*g0sD+obOcoMN&h;=X;_k6_Tb$rKRL%JDw@J# z5hJK14pf4&4|P*?@E2w${hcp{aUwAG$CLN;j>y3nBR&qt{&gSVv2LPj!!zUm@TERSkRL6Y{C`UT*9egQ z*0<`b#7C4P-k^Gm%_W11{s_5)s1t_W@94WC4Ulrl*7n+pM*!>fLf|dgvdB>qW2P>c zTHfaJWOg{c>S}o134-7JAF5W{Dg?$J3Tna+UPA$-zO+5pJ;WPU7_X7vJNkqbvX;N~ z{BKu78zdo(SX~O1UJuOa*Z7H=g_SEh;7QTyg|k}kWd2P_eUIsW=D%&@zsQK!h=me6 zrqBNm05GC93f4hz8H?D?*v9{X=lJXO|6hE*@5EwZej8fVmz2}T4QJhTBEPo9W1Q{=+GyA{|Vab|ta&IqUT&I#xA)`m(1&!p-|OO<2;y8)t0_L z@i2Mu*K#xw>(U`^7fJ{TXotT6@H%9U#lt99i%A+g_uZnY{=JEU#}V-)?dHH+xQ}Bt zb^uU#GWt>=|M0LKy65{Oj-^~0+Wmv%+J5KF$Zq=f?(eex&gsFLgx_9K)U@~#5OII@ z3bvUkL`S=|*D_n#Fct*l{**E~!p3oTP=aMng5Qmfj~nm}iLdE}4Zbbna_}Kp%M6;0 znSr%7-lkb>ld*ZKSK0X)+TQ1iV=jFES}0^RDH2-}WJhJwfgY^({D<7jB5@&`Naz#wMsPPr(o8gOWa4k)MX_-U=7@De(|1Jkv) zISIwdBXHcubo-z#RktGKeB)PHpEp=7%Pcn z?IL(L*Q=ay_HHuE2X?Zh{pv-P(nYIfO+A+VlO(*wEOkdSrX@wUS_LiBj0-U>>k2Y4 z?@T+zjmMlt?@Y^JhZ-ZMk1xHA+DEl73lj_7{AZCpjEwX_+=l%7!{RGtoj^$atlwow zbfo|kP;ctJz(#Yr*|~Gj1FG>I(&zm4J$7oDWQ957W+U_ADqw{iEN~rsMc5FENFwOL zf4*dp?9MjE$;MHG5YyF@Gg?_}F@-%3!}ph26<6_Od#JPzyuqk5Go?Pa zSUcr&229f8@%R}z*+!?Ry=jGLhn)@C%ePEaZwGKdQg^>BKT`-AzPDbsxQpsn1wXaN zB7l+ThIpYR1#ALHLjr{)e>cm!(>6z7;G>!xkfE^9phJY;7U{0OQdvzFZ|6z%cHRb~ z{@C>3*8<7Ypn)`!0}%P{wt`_n1M;+TyUO%$C1!9D_WzhMRqB?IFs8Tv+{{Uo*M3@J z_R31A%B?s`QDN9|R)FD6cK!JgVYgVCG%U zV}M$mJw^U?^$<|=H3(j0Q>xmg%;aFt1OF|lJ##VB`^A%G^60A@+Y4~n&NXYYn0MRQ zR=@aSDd5R_Vuw_?14Rt^aKIHfUn3vIz54bva6Y@v31yC(0(z4fnSSXZ6Vo~8cep7J zoNtq~!9CQ~iU!$Sf0TKF@FiS)3OSo3oMF3;aWDN-n{dRP!P$9#aN94g11e?t()=U_ z*H9L)DbL5tz;4(dF@DN!6o2iw_4DhX|HzeETFZVd-06Ii60CO?%)*)hiwVYWnJd;0r92o)=bkkEoZrOLAxSLC{^x?eTdmfZXthQmk2+2()Ec0M?TH`{nTnctQX z^|NxT&vebUcn{2+5^3+NJ~j0@M=H=jM@r6NP2oc8|KEd%Nh!N?Ktz= zNxxG%_{nW`(cf^nlrsnb>yT0=3#^g5kkMFU=m_1q&n!wmVZB zTt)eKYb$opEe9yZ&a9+}Vp8}nquxHvx8g!dO3ML^?LWfsKca-KNXz+>^n`>s9aS9c zS2*dyb=A9KpS2#h?6zcl>gnX zu;K?_c0Gn454XYF-8zX#sjX%`>|BtKuFri~SUuK>opoExsY}otZ!&4neD?VWl{bE$ zj0M&wlo^5UXJ2TE1*TYBeUr5$3*=4a%-r}veK?+ry5}`(s@&BjS!cdcdAV0SMYW(~ zg}PRKJ6Z&1ZY}Xmul*BjerfxJ!32)vGcDzt#dpM`=o+awH!+9O~ zicN3b%v5?{9If0>w*_$5FkP=`gN@hNeoSn#xHGyn-rywsmbV^edXIh<_4SjiErcGf_R_(0J2_>-4tKjYwEd2cWVz1KhoQ#I_V}5tddz{b)IOKY7^<2cSZpXZfQ|zPL*V|Q(dwT4{tS;i&)G(BGhJ!p0`<2Pev`o9 z?rtfk`Mo`|%dSqb+`2kTwHYNGg~fU2!?sW-nh;o+#T^Ojl0EA{Q~W1YE4)0*}_Rvl?zvDBg= z>3uD@O3gR3VD~jh?&>f{eZJY_QQDW8t!~yv#z^UURaID^;$2@1#V(lx)a##zJ{Gt%>o>FG1UGu>{W~-iRaSk0MGS%ys`kWv~c3!nKL)ASy797Z!>;bxwc?~Xfp;tY&b zfYnqxU`SF|y_T9@rux@Vabjm6Z9Tb5sKBULT{14`!(?4#gT+sX-RyU}1y>fKM3vVQ zE=60es#Harg5?1Fs>YV9nbC^R(?9#<4BCq<9~EGyPv=TSssr}(4NJbtkcfyMtE*XS z{Mh&U=0<~JzNv59Z#SV=v&xov_CINZ3u0`>vhq2L1LcIhj(_MkfLX-XhG^f}e@UZC z^V@9&#AX@m+28MoFH4@CC10ScPx3o1DP;p-$}t?Qc-tgG)yU;O4nGt5%$^Hx-BTs^ zajN@YL~`?tew}%3R@wR)C5Fo4;a;f0aYQg+{Z0GLwzw0T$j6FQ6W{c_{Bq8g(NoGa zE~`>1>Nt^mB#+&36`uHPQ;Ec4krS=HZvD=V!IMCBQ~TM97~6`Rs(8=CIb~*M(0Y?{ zhR$@Y9ASSKYku>^D`+|#r10hQa!V+T;RHT&3Yd)LL<~fClw5A{u)2xQ4##Mdcnt-*39L^ zB`~{{S*)DQ!74kyk-t;Uijgx_yY;H$-P zsDHs&7;m--p0;5dkdax6si*gT4_bS<%f8dbwYymO=W@;Py~zw1tnglmvV+`o&jlmI zLpp$(7?PhHIY0FCXHw7MYMRKBzMdI3@yhqmUvzI@(|${3CyI%wO86PytT$*@-BEFkd(B84cWrrp7!wCpC#yEFg_fQ$YEHo0&szq&Z-S0-dbJ(f{1GY!4-a zO#@DpF+vuIG7?)nau+|h2CqG^5PghfD6hQzg~w)WmT-C+s9GrulKBvV`SU8y^hu@| zr$$M^H>+?EUrUB9nw&Sf!iI3dv^n6}A-niP+0(@KNLC{Mv7W05)3g$; zs591_I%U&tA4O$#8lLKo^w(Im_Xl~54UQ^$*s*B9=>biX9Fblk0<`NyP3r1D9qxMy z>1XZQC>Fotk=^f{_@i2A!&ZDR07BloRRWLTrw{Mt{r3tjd>Rr?3ydJH#Io$_!&Ke_ zQls5JyMO(9=3_XziV-Y{?0)P1ib{OccbKujc&e!SC8WpS+M3bAGs~dPR^@l-_F)>g z4OUoQwF#}CeP3Unnyu~I;J30uUryh_UAiNjJYi%kmg{qDT`=6EMfDH)m@ecnDpB9z zT$;=z*dHM&Pf6t_sE%EP>)>wzr(bz3Fc3hZ!)$k4ayt6GWQYh-8(_x$td~B#nCnZr zs7>&cOPNRXT~ms#YMaKIiJIC+x9#(Nlr7)h9-bmay;3Bsp1VHf46@pdK5HZDSuB*4 z{u{N`yAt`27K7{q`Lq0w(nM7pmFZ%jf1LaOwHst1ZfG3OQBp*|t;twa(_-q<)$dQX z&|&J5QO&g_jY5arN_T8$C0=-8>UnpL`m!Us|EuTU^6ik_&rH{u8v_YPvg7Rj2aCM>Vt?y8C8XRqBU>@s+NNZrX$hkX#|PEhvJ}e| z6R$>>dD77&MeHlXi_F6P%gP2US4DI}MH`K^G)*P}Ghn;1y$}8zEkUl|_seHQy=6cB zwfj*LwiRHP_fcb8T+N5y(Qbk(W<`hB{Q|V&lNJ0rZ0O=?uv;HK6NZ1_C3-lqIhk4F zkvo@RP&3~-(_YowUb*6{6*4*7!DdEf3_2g39CbGN6x*2a9Q+wDua0E#K$!R>i}DKX zaf1@V-Y=&&@Hh>oLT)u{kd9}sFK=;f-o&nXPRUX;2tUp{Co=^VFR%1_oua~5dsl3Y z5BDjz->%aHTr+pw&FFVi0&>Q(-*S|LXw6nvE~)*@fgU%EY^*08xEJr&e61+c#4?(5k_~DhEe8~(L zA>s1l;()CgufsO2yURWK@r8%g=(O@5`=sVnirWO3FR%)>YscE9^!4X2`zScoY{Qef z29q834xBqktcD-g7GBWs{ahzn2mQ3d(Q=&iz?|p#N$1VWN$V3RV3~x z7T9VBKW?{AnLC-QM*Txh7I-Ad@_2v2GAIIA&|!)Xy$eq2v7xryjN{(HOdx&s<@0(N zYuc%Yh%VKgBk)3HwgL!}gMSX$mF*xq!+Ku1E*RdN_+x-mI2EjxacbL%;m7N>A@*J; zKN|Vl+Mi!v)f|ZeT=ag_c#ncj+EXOvS`zIug06P%l7Fy&o!ssD({0ptf7@S4bMED` zdwGxc^uAYefG=62B^d09c|r295afO7pyrI7#!sE#dpq#S zw<0g&Vzrq9w)3zO*KMavc812vK5sR0BGc^*6pes*#b4?(pu|>x2=c-s7#9J)q~Jt9 zdr#EdN&3ymSr)@CjAWx6?~nCn)k0C_t*&TD8TK3Wd+Ja)hXW>En$KP-->qw>&(jcd z2b^@ma6Yba4h z(OC~?IPrQom=N3aIGoG6g;fVQ7t~On3~D>XE7Qw8w_wI=dq;0jYb^>C zNuxVI>o>f!M5WF9`hv<)PL{@MZ1x2OpP)CL^pwy2^-#~xMpv~uz#VMJT4ZI=C;UCT zQB&BNn|~S_p4CTUG#&q)yu&QfJH5Q_Gpo>vpaoj9GoYW_?5cX%@06F+`1UrFUIW~A zauSxte~Fb`W{USm zj1L+0MC~4vp4WsMAI)TI@ZkiO2G)_p%35q6lp#^uC;28XFk17f1;Bam(uw`Im(abZ zWY;0P1Hyt2(8U++9O(aAnQ`gPOIToUR&hZo;M9Lf(){h=+=L?7UaBIh%k@rU1?d8^ zD{r`b%aTK&WOPrHIEQHxku(rCU6#h|E_Ido^g8XM#>VSD4s7z@33WX*-L!ryt5 zkOz}cw$WJOv*KH3*%z0hIWn96(&cND3EvUDm}`9TyXw~gz3pI*+}k!58?Y7H1{`}Pep9d*L0qSqFf zRPGa2xtauP88?68Ed+AmjbaGj!H!0_aGjhOyEJ`{T1<^bmlx>FXqtB`UlK2Uob&By zOR`G6-?RM8^5C$@#CLZU`+rL36Z|GxOg(Yv!Q~Ex9KKAjdG*WLBAi|W2A0V4*h$#Y zK)L#!@c6!lVitbYy`u!qs+df>@T*qJ?jO@gWPy(oS&0 ztnD$+0@{g0n|4K?z5c`Wcr=#ZGosupIo*evo;xn%o`)wOm&Gi))m;WegyI5SBBseA zK7{&l_m>mHFSO{AXHAKS)A4^El9|A!MDm%Cj+TgI5>9&soWc^lk|0*J+Xzcl{Za3GWE7@f#vu%B|CmrSC4!hd2m^*3`|0phroW{*b!z;0d2ekYRa9fl$d;`EJ`SM}Cie};Zuh;e9_Vji>(S^P7| zxLP5r#!2)w&Bk2*tK0UE89z5ge_K|jzZt;Bvy3md*Vsaj`u_dKD!P+4LQ-fni+i<; zRU3NMBj)`lmWo@UZC4WDpZa;VArW@0m@<;~S#q9g~b(C8K8#Li=B8bB|z4$~#I~ z%q+qsDVy_Kj{K9O<8TFkKP_Q@t=QfN={LTDNNCHx*`kt)M);+tpZwW7>c=I+9}fcc zpJu2CoiP2HR_2>Phl6`CO!0D+A%VT=*6GE^7^;xDkWEQ$lUMr5k7cETIFmPLbsKbF z(yB+&1ypwZuox~|wRixq-zq{KpBZm3^i$8WIe+JRZahl-88P^NG43haU>^Y_JH{`m zdCrn`Z-on7=;($bZ5q^ z?X29SD66gG>9c}pezfwoM_Rm9-#dWN7f5rzm39NI+LWPlhwVj(OopbZcg*DEa64|y zktBLP)`83R_O^OJhnsVtMSE$iw$vCAN&}4u-MldAN@1<_SiN20;3I8X5W_KM9j_bI zNYbG6je|Wo=ZUGE@k*S~zMv_7m8*~FLd1@*=c~?ZNZeZ{Z)*7QOd|f95i-z1iwB(~ zg)Zapr(Ljh&2edM!6$vF%#)!XpyHz_#I|>b=8bf1yLs?p*3tp`- zHpGp9%2^6t==2RBPDyRy>eXr&zZURfOq&U0eMSM!}6$X^$GtE!nr06A1U9*jASsctV7^)XoQ<@nvt*s%gG=dTb}*7$xZ)TWjiy=ae2xmT4-IuX#XrAp-8YPxY#{0?Ra0O4GrOdzZCo zb>Mf|qi2(DB1xq^eQj4F>ahap20?S!%wXyxGc>UtX$@8!}M9hTY zk6iKj)ZPR8(;u-alWvceo1z1OrcpCV?|}q8l(;iWi)DFJ24^0#vII_0tkXU`$gy8L zkQS{FgRSDGGtGOo#p7%F{uzuQg&WBn#Aur!_Aor8JxX66TM5@zR@dgpDGkWM!6uv_ z3uYb@rZCp&y>H2jO$jxxe!X^!)j_3v zQJH7f#@|I$@4TS#Ot+ORXXl25Rgwe~N$yjYj4kEl8KZr47cL_SHZ{*BWecB6CZn-@ zTv>fTKoP$7ZmaI3zf&{7njunW`F4`8`3Qm*kUjpch?u>u{as}r3gf_I)m2ImL(1T( z-|74Hs;v-j_NO%`mND1k_9B?w5{-~M?ZfeHnari94{pyC|LUW}!K`zVe$k>jWw4)8 z8NvF}FzSWv1qfWUB{FijP(ZXix#g9&P*lgxbFk*0s{F>|Kq~P1*9e-ZM%tiWs^{^N zOr2R5VcJ$L__o=tQC&Bzq}54))y6um>`?-<O57Y^ZfPK{Mwvlbre;NzG<7D_`a?a!)11>#d2BmJFnH$M{Ei#i+dB z;qQJH6g7{%$w=R;Lyl6qAOjZ{tUw3BB0AW;NzJ7V#)&2TcEw0TlqMo{(emv>@9 ziw6IrkwU8()1{TB=9Fb4u3>%L5hW%La&?Ng9^PTD zG={pAe@)MVZoq=H`+eIX4v$!B~WBkHSe#YYV+{-0on1ie`-=S;FH#MVOw5*zp?mhZ^pxxLQ3!o!jSHU7u33s?U)x@h#&=f~!%(162< z^!_2)zW_Fk3Zx^CPvBYkY8|P&sY4}$3}?=ZAifhbyO3Nqb+!7(vYm%t=(U>_kF5Kp zJ&M}YE!F^^43b#~o_f-ECR$_i^Qv}+sfmGKz8Sj}QsT4at}?tNnAO=VJ~2>cf{xZD z|3E8!AC$_rHkLIm`Z+N6{vP!iax46)QdD5-CEaWQ z8#SID0WvPO;bM1(Jo+<7>~u@wPfJ8nzDSz~fnqlysIB1>?EI#j3lJmkyCb|(2IsYg z_bS-96nsA=1iCwJa9#;BOi%BN`o2+btN_XY1>H#SQCvWFo8Qb|(yR`H&?J@pAPRVz z_{DD95V0LjbnVt^8ptHyc-0jgZZUFw@e;C0kE!WBG@33t_R4WsPnAJ#*?5wMoLuUc zzAkZk6&G?w{Q)#1fY1CZe^|4l;j)Q40?l5nh?#PDJLI_@WZ&+4g|G4K_b-v)isM{q zIZJ{mCj{)Q4L$^u3Gd!*&KEW8EBy~z?XN@WgrLL_&2foV!QT0W!57B^jlthu=ch+B zDpfSIup)XuhE|)2?)4r#)HGSz!3iH(=8g6yyY(XvYSbFg}<^kmsI`Jp(n6xyA znZ&J>b!}VI3y~O|B&MbKJ!psmF=ef;dbwDgMksoN5oiRG&PQuY85_ozG%@vrMslU& zfmcO=WyG*RNiq3{S`&<;o`lFk&7>dcH^Wlv4G^-~S{Buu>FiJ(68s~qQLV`IBtPBO%qz~%pUSA}6Fka2 zZ<8`U`h`)x`o1+jbR2BZp0WnmEqgh36kCp|XZ1Xm;V$Tf`i~!cobvKt)OE+ zX?{86cWQAiF@N=+1V+!v>u_E@zWJtIuaqxK!1L)^4VGS+^jX3D#0bqeH1@MLhy%Z> z>#^(dI;b;})<~EOKJIlFP%`KUF!?_fmo%DvTu?ol8YzZ+jn-1;`Nf-X-XlpcQF&Hs z8itpetV#76>h)vl`IwbD$gE2M^2%?xJ^|jmGr6~RMxWHr4=ud^N%b;I0t-P`N4u{L z3lB;XCEP59r-{r2DMt&dW{AlbPES4Z>>i`Bur-LmFy5V1!B#=jLXRRbW_BpHJ<#Im z>~`%ZqufsHPaby1`h(U-+6CS)|MrkAw3e@7Q5Ny$iIcJF1dKp=jV-h_@a=ny!-ZcT z9N&rSd707Gvl6vWjaBIsX*Ak=Bz>rl^cXPbN(ICnymS@+p|l$v`7Lkg<%@-0L7Tlm zk!&D?^R1kr`jV~%V~nDY5vhJ%AdzEMJqABt;r`Z^x{1J${>{@y zsw+>8QrxIgJVD0D@;>%hq|ZSw9r>q-&%VHhgGvbGl~*E*IPJHIJxx%w6SrbTo1Qib zvBw2>+|wY`C_W4N?nym4jQIhzb$O~*Z|eyG_81k)IUIe{BJJQn!z8aNO{IYa#~9s}F31zn4w*<6hoo{gk7P_q#fl|D%){ z;x9a45uUo+gSGK2_-pes6d?u%?P#0fUV0~LUlUT&&(9`fwV3teRv<~aY4^5w>G97)cFWi1lSIh`Mom&Meb zB#ckqW*iT`_8G0)2d@988vabD=7&}u`231;E^aCRX7KGzYGIOQSKe(nqsESy@o#ea z<(ZGQws?MSo4VOdt~2uBtc#?e@M>;T<>Id8@85K1FHnCp6_l z9u6L6)b6naN}F%jH`2x{S%|Ak4iw3llYCd2<#-knU6Dr@{5T%o0NFr}^eF?Qc852+ zpIx`qx0RntE=U-IB+*(EGwsGph3YF7e1iJ}mB>2FYAQxS=cqfeCxxgu;-1=>LdxC{ ztq91+93h8-w@lwX1L4@L#3h%_^vDNx0DWqc{xM#M*PE1<)D6epv}IfE^NmVv!EB=C zLytqEnB9f2EiWSRAg^5nJaWP<+P{h* zgi4DC$RKgf$x1@`9dTmWa_gDW&|q{PaYwTJo*lB&Z0wwcsnAY&2CMDOfUmetdryy^ z;#RIz#du=Zc!h<9eiIwv>b-_2eDUr1#qIYziE-ygC4$tanEpNshDs_13=(V152wEn z|51BOV>6oH`#p7DyW>wpncZc{A3D6Awc;nB3I+e?YSvKHd}`3X_P*NO(DV4fjeb+v zKO)7(g+xpmVaH5^b>^RZ*Mb5X)@k=bLPD<>yVIjRqr~P=Uwx?Hr>?T~z;sAqtnp+f z{HE>w0)vYz+H(5Cvk70a#Hs)hzBd*=o1m<^)62H|bCwTLS0BR1D{;^qTTA%dZQzFCKHLd56AjTo>!N*;|6TJ0+tdCP zm<*W)R}@mpg~g>ql9rRB9)@!k>dZY{Xz#IrC01p6BSS_=|C$9rMA#V36?a^iG@W=4 z0Z%t0d9}Yb^K0NNnte)FcFM@!VQAD*lkB0E$H}=fagf4L(W9B%r!dmne!AN&k`jX0 z3b*m@)b8xrL#;)fy@R+?dR<6cjeq&QbSlM?Y<^YibriD1jZ0lX-%T-bG*NBuQr-FO z4w&HJSr_PSqVjnm(*Q&JA=tH0@_YY@iPHMx4_+ndKfV=j zrZW-~mCN*ocxENcSb9Ykz;9HB_TCMlThc7;*917G22a~J@#YX-eu9tPsU@WzK@7Rv z;6hPHTtRFBunU15OD-y-%Shm5&|!JYm6h;Zx=ejws1+Nnje6n$moKG$M64w&OdWp( z&~z^t{HkfL<E|Xx z?|yE#2m^NKPvx5Na+|3-LvI~dJAk`57g`CR)3tDtz2jxr1(=Fx1TZJehvY28O1KXc zaMAF#CYNvhE*H1P@K9}exs((}vxybGW7#^Fw-n!n3bInXBPpeo@j6~o_JcE&^)e?| z5lKYJ${2`tZOKR5JUxcy#nurVbuW^_GJd3Mz+X90inxdIIo)dW*)00nXM^+1F^)7Z7zlR}&CN&~5GpoI}x`aohJ2h6UVa2u80LqOm)W8&@p9ZR54JvKJW6n0kg=IPOg8 zsY7yA=uB@|6@G5AtzkTgaHa;xy^9?G7AcaYAM)kd8D_$mKK9zz22xnWvn!0qP;R!+ z9D80V#-Q)t{B4{{Zn9vNQ1G$X7c_$B7_RYseXAHZX-r|1!L=r(hO2WNUmQk)JL6;Bo@CjLEpCK-hAmSHedv-yr+2J2UwtGj zD8>qDEIK+G(?BC)DZo6941Fnytw`9Em=~JAn;QUE59(ELXBX~>N}(~_Q_(h#ASl5_ zEu1XRSmQPf>|Y;|9Nd-J}ZLd$As(dpB)*sYIT#(T8QL(FtB1GYc==mJ{Z zMm6u2?56b4Kfr7m>m(C?S&+ObXI+x)h^63<$h%pfle9*8Vqk)JzEwgv8t}b_eGn6s??7ZQ5zt3r!2fV=S7#@9=hYPPmvTtaXS?k)j>ySuwvaCdhI!3pjz!QDN$yUXD2Ft~h^bDyW` zz0aTT=dPOC)4g}EwO6l8TG&u^=PT}`uu1*9D{KnN3Cv|oF zG$W!QSabE&@t&j5fFP@wVo*73Vd+EbEf!R>yo$9sdiCDl2Ed@SKe$8h@5nOR4Ja@MFx7D&wkL2Z$QMr zHqo9%j@p&FMZUed%^FuPM$pj%F? z*4(w4ytxE7Zw~bhTqmbGyQ!0(^zZFG78)l0bx&RiLG+qz6ZH}+3y8(1eH>pUez~^u zhRU8(1NOZAj6XI*g9Li-%|oz4N>!crR*p3B93R0|UmAMdv>ZA=K}xJmeq8m*YByhC zuX*kQpB>-8o{#Vjv#SShy!e-MF?euu0DkY~8o5Xo^ zZxD8%XQtVlSC#>d#|<7ChQ_L_=Bv5lNSx~BLXCz!{pGlLYzc|Kx|=^5S4>n<^Y~K) z-$zr6_z93($%`l{RFC$?*~!^*ws6GQpi^JWZ-b`ArlhM20{oN+lL%9R?}LqBZ6Zwb z1I(-28Xst*N87`laVp_i;I3lif^_^;aHybm3k!FANi^lB;N3)5e1O+B`ztG&hHuS4 zw(g60y@k?+R;|I(6^8h+!2gV#@bAcDNy>FFak;^HKC*U^3Im>NSbT-ZgX2=R?vaD$8DY5Y&ABK6h=&2k#>6#IwishAP{Ws2`c|wmre%xfi!qUlW z-zfx>@wquBDV5?{FHLb*e4De8G3)T+W#a=*o`}q(<*j{arJB>n6H;2+l-UK6x?(9k>>tW*!P!{r^vBZt;Uc$Cap@TdOV) zy{3iwLsK{rSmBtC>6Z!%&i92!3!izdyu;vZWG{YADXXnqe}nmzTz>_iPfZT; zv*iDD3%LH?FGjADb8Z@b`3L{I7qe93um5?+|GLEe`ZstFvAgro;}Cscfj-YxxBtT) z{?}{Ky@IoVXv#L&`5`aJes{fedt5&8uPOZx#^})dH-C8fg@YntWqQb9s-&9T;NOG( zKbp{g{-+1}ZyG;+qOd!H`YuA`&zIA+>hnJ@<6oE9y#JX%O3VMx1O%grQ7~}j$v$4m zF|qe%%04=zO^Xh#3yBQa(x;0!fUVE+(kq>5O_T5I8WSgOpuq%k2mKw&aOl-y)IYQJ z=COC_EJL-(MxpvtRG3}XR>PS0@80*{+0TE0B2Dj~sS)58e-9M;Q!H|tGMjD6dK%>` zE<%rm5dG4vK|@TgnmNkZkiqVA8(5plzX)0sC(M5*GK7s>%;5r2mlq2-zO!BUK~25< z>H>ovVLp|b(=O=z_WF9%v}Tw4`U)W}&o8*veCfnB3wzO>(dK?hJBlyh7+);soiRE# zrnfjlMSyxVoksvXU5msW`i4bydvkMil~>SUcFu&WAkpIT5A~oW7ZuK0Te@-xLs>sv z!1N5RFlg=_`_99ct%XughMK)J6{7EvKjedH{JvnEPsruKFrd0^`h4C93b*k{R4F`b zM1WIP_hYBShTEMq?M9xUv`>Ah%aY{R%(v%F^AV<=XD+S`uc$@8cekvE0Nd3nI$-xU zVcnxvHxV1W&Wp2@4yYmo0nr$s?1m#)MB(bK70ARyxN7yE_uqZ&V_Y|5KRYLiY406v zI*L7+cO!Qiy@Gwm+@Y1@bE5=->b>**Q|H}mhWt<@OLf;XzF0_DBul86*j+#Rl#-HC z?Hu=W2p>d`!{}aEsaPb`3p%ERsj2DRD4qS>H9Af4p=4Er2&|SK=obsDU+voX7OgY%KoZx-NsU>iiq2qqvI&vGzTcu$52}gUW~D{zmr0 za4Oa^|KU3pE45~WAw51m!A>v38Waj96A5y=pOB9sckC!uRhfOWTZw@I+@pXtmw)=v z*Oum*TIWv7T2~oCE4v30>I4ZK4@U&v)?4vb(oY6+PhzNvu_Vd|`GQ(lyS_w?D!)Tk zdb2ayNqUqwAnzT^_Pig`J>~j>!&;W1<&k=NSRE~qM=0vdwO24k5vJYaht|>c8qCv zTd~n>fTR50_xL8x^i)e>LIb?GzHE?xvcu?mpu9&6+M=gp%nv&ICcV}c<)nhV ziv2sVAor)miCf?9-k|{(xU|eCF@^U)5@T<#4@&OmTMo8q?>Bp=M?D3_@45)garx`c z4QHL^ryYmos6Z?!Y^BR^cg=cF`3ucQHiEUfMNL^EYtV)T_&JbUum?u5poRQozAKHu zg{q0EM5Xlty(W4!CQlxIu~}3itz+UYq@(e))sNuYf1}nW)Gdw(@Vk$!!;LI2&F>exmfl$viKX;3Yqv|(oq^CLz1F*G~t0(N~SeEHeKu~=BG55 zU36JLc2x2&9oTd3mBr}RbdB8G@XNPNhn`>jC@lSNQn*~KUOoY$e%c=Whag|m<>S6! z(R+-s%5h4>CVj+q>CZLrKu9)DJvx#PdHW$JcE~c|C@9G};BqFR^};dt^oLiYn0?sU zmJwGvb1lFrXKW$}Aw;bKubp=lBr-O|zYpM()@i0dCp^X#{%>yKabBN2B(00;7RO)! zv`3Db`|QiJ0TQ?I%(}yJ$Ukj213|1}&rpE^^-FAk%a%S}Hd@U^W0_1E$yc*+$+qkf z>q52ir5O!_iLZ3(R5uW*h7Y^gn84n4F6LSa#4o&HH~tL{+i2YG7rI$J(<)?JM*LRu z4pzk;k_Cuyz?TQ2J%GL3c>5pK-9wO@PF2<4+UucOaf-*8#z+v=p9`(hpDbdMu&+@&>ydVJ6RtBki7K%ACg zd>>G(yto;i|65(plgpdT5@|o1TXv)#P*3pURWfm;LtQLl&{UWi{|{lyXG1K@8hH{q z7)D@|GI=tLr$vPQ0otbkk;n{oZeftlMb>z2OiRVo5hvc-dY`KcsS&0 zv`xPF`&Iu9^H=D`Zp9VC-B@>02lw(cF~8Cyj-e(r=q23qqaQK9@P3hKAgZ(cSTh+I z?a1a(%Axj8WpFtu+NkS}pw&hhp1<$xmwRKIu~B-E!NOd-=MDgbJlH;!exv<3(gQS{ z8qoy>_-0eUX-;?1!b2cuEDj*T{gpY`b@WO(@KOaZ4$hFGae$n1|nHZ&2ngo3H6)$LgKVLKE)j#Rh?ke z#oIdrgpw|L>BR4h&=k7o71muufE2@gNG-qBZS4?YVUw*k`u8&aw@a5UBF-(xv59tI z0l&tF&^(>#%FmqlYjPu)K7FsVSZbS4{aJDh6A#*0{4E6cza3_1kBP)4Py`t$_CPME zye$t=P%lZ2dzXV*+Y$Odp5g4C)sa&U+px7O0oYnY;Ee1=Hl{MYiFl&|FPxO zkVQ%Cn=)2Y{>^btYSXr@nQ}AZH=`X)jHL=1_gy9kbCRRQ9kH>aP4COS4zLoavk4A8 z2?q2Ggv_WnlP|v7>8&opIsAOb@iO9(wB;I=1&ycdIOUPMReC%#Y8rZz55OW97K(|I z?7S=LR^TFlxz~mQV`lsA_@e+M;gj`w*FAXs|yR_q@A}SSWUjArgpz zsV|`jij(@R!19B&E9X2J1G3|refOLA%>B65tp%!yfd(4k^PrwnZCq-AT)a(aGCo@J z!&F*(fBG?mTNv>5Wo3zVpp=~XgKbde!sGGQzs zlM$gd2^&G9uL4(?P$xs6;q6L<+|ukumcDtVrW(k}ZBJ{PDKocSYHrq&jd}fjyvjWDLPYN?6I=2DFxOIGHuB$DMHaz3-UO8`RqGZaK!KPBIxyMS3caq z>^7R8Y=(*;kwA9ej ztKgURrHD*3sXkC)qe`OY;4;umKj9!wqt&|h&63)?-VL4HVerD$w7* z*zr~c1BZ~}gp(}b8gIs@$HT}TY&X`W3q*x;GN4+V+PBtjj6xYUi1X zDG^>erGT~C<)jHRTFCSFze|%SPlVZg1siBOCr#()K13~dFD@7*1#l{XW z`X8uUnEGWb*EPn|>ZeJ5R(KKV|GBXzdObxC+v@by%s-8H#J;6qph$c=^d@SjpfSZ( zjOvbL_j%zr#a|^ea%w|FLdsuWrrhDpgmU@Y=RNt)7k~vpL1#OyVPf)Js zTVp8(mU<}zd6t6gs3;+QgK9pFK z4qpijD0DY}F`274xO{;fC((YEj3UNgxZhTSn-V5xg+Q^@z1!jv;w=M4y$o<+X|uAW zOA$&a)7LF{;`aYKWsp~o3dYdafh3GRd6dz_#%Kx@WS22Vf|_Qs*OnsReQJ^wbZeso zq}uW@(rsfaG1W_$r58vPw?F1Fv%dZ^(0RuDq(%GrnnT4={ENvzs44+I0exR^kw%Yld@1;_%gsvg{=fSk)O-s|`Hu?&)N z30MNBVN|YT3bN~6Z<#R`I1Ok0=iM~zSRi@5C-2rsN-=*xiJpXi@+%Wl0K znAaR!QaA^)mL&~Kpy*T1c&~*nN-!^z=C)1eXkNC|t=}TLjcOTM#|={9+}@!Lv3SR0 znJu_1f?5P1gs@lY&_hMF2$GzXk-maY$%EMx5cv-sWbz7X!TL3xJ_vILi1gVuZyLHY zAx*q!)gR8qQ_z*+llo=Y-ax)O>b)IXyRe^oBmw6kEOzt4E{Z0zxPPx8y<~9M7sY4M~E}3FX-I2oxq68MHLG0rxu0Lf$*3ZGN+FNlACD zsWRhjxu9BY_h}mACg5%;=)UI6#f}Xz$Kf5DUwmtpF#$?N3qp$IV!>-l6!K9SLjJaV zn3SD$Sw^tTrS!Yt))Bl?BPrpTj?N{fl{{Z4<)&nYAbNtsom=}+z zw1-<-$xS{Yvz&vg3sOM@9Q4K>t;3BoBB+}ZdkBjpb(>!I;A;o+Lg8C) z(1(8e%;4jz^8^aMoEp57+s)2sIyy3+uXe`%5f=F^GUO)gCFo`>-m|mb`LHg<@Fds# z*#XL)Z~g1G+5Q9vpddI5X^ir$X{Y#9s_WSJ27J?7LDnxD@{<5&2cN}iHBqv*RVg*4d8CL$waoT)zC)gHZ zr0U>!FNim89|pbZvkSyNvr82-N)TXUc1y6!Gy@vOH{wlUdJv9hvMn8eM}86#3M|&g z5;sORNv)0xyJ~Y0>)API7I|@_55}iIFxU6%y2_2a9Us>;T4TqzT2sd)i9npipCu;o#65b-^dkHcAHYUN*6wmF+UeznJsT8)X?U8?eVpewe34?r^3U>$;@zM`+`oQL2b(6M5HkC1>+s##R0({|mmJS5ut z+d1_<-gklZQfu`eC9sG&>2i6srXbf3>=Xech{dk&YPf|~TV(UR?&~@7m+)wW^)t4U zD&I*thBN6T=P_l+F|+Ea42ANe{n&I8vH6_2Jfd$RtZFmYjeW5wQCjGVIakf?E6pWN z9v9Myby(eC;EkEfY@vy5mVPvo(Yyrk2`#mVz$1F>WmaC0$hs*x+XMS#t$iS9m4RB*7)~?@{bG_3K@(BU)}brJj(zy3B>5R~u(Tnr zGmwrqp9Im6+_2n4;2Gyyxamm4Z3hD4c%UWuX1ZykSIFnxlN+(P zU3Q@|c5tY+1Q1frSdS_=+&7kM-<=`V{c7ADL`zMYE?A@e2pON_nHiMkafkf5>A2!g zWWx}H0yF!2Vv1wtp$e(WIDQASsla*814%m8X7N?LnDBJj2B7m#j>^j~7zwtbLV(;3 zKtvhuN@CC$&lNoNS7-SiT3HE8oOJr>Ste&44%r^SU?+bxiEh$E_3n!zoXR`P*}s zc|Y&9x*wR(cT`z*%5klV<=#%$Q*{P-I=49G_Ly4xB5|Bqt z7URj1PU6@UQ!b5yyz5n5qxHDMwBNMmiPN>{uMF26l**S^TM_t|KG+X0WTX8o*_xrH zDZ)CCPc5ig;T6f%N3ZcCsVr3hL@=d{cQ#NwwX~F8MIMRzdNrAm-&kBSS<_6dgZHo& zo>(0JUshu1obhigPsk9tdy-JiHU+Zmwv*JYPuSnneTN?PPgmIQu3+XMqfLJ$^avqZ zexx~Yp-l4KdN%9r_*LfY7<>&efS*8d~p0%DZAO#~9Zu>$5v0&#p#j#I2cJ}aesL{8E^d+$#8EB|HG#JX=%)s^glW(kD>%^A!%ebziL`SNBJ6+fc3`$>ZMDi@}wO2&KVve%> zA)F2Z>#et-;0E>2DxM^>2jIe-N!KJICL+JKV(R45Ug2!m>9@6b5BF(#qU)XCyCa`VA zFWl5pU7b@cMipN|ljI1#!|9pUJ=)%fU~;xoa0fv@^7p{k8yI*_@_N{j#mcpT+79{D z?wf&;GcE+E+E3Ny9s*FP zg&t&pL`&DvTxv``()DU%_p+&XFwvPxxYak!{+yD=Q@`5yCpW&w3qws!vbF-piZw(~ z1A_M)Xa8&9Wn_O}6+1Y>r3Sr-#Og!019#o{NhSF?!e_dYi|(l+R#?cRD}@+3N}IMU zUGQJ0OC2Z^&%ulKU~$fU*<2=Mx8rbe@;Ys~t^?@rcWp z2Ff~DkX@2nP(s>csxDYIHNfFNgf%NKkd}07JM;r}^V1EFqG59qj~pJ_gHkJreV%Db zS3-d=uJuX zWcSoeWoHXM=(j3}eqG=BaYfqwdI&$502m)@_^&+MDEWksj^z=O7+!N80Nk*C4Wdv% z60$jWv5*@b?$M$KnHOnWG$&^@`{e{=o_oES1X&Dtl6m5xpvmi1`Qns3hE8~XimC8P zQ;YYX{E=}LAjc;fmg2)Ws{h;nYwShmAuA(5C0exJ={Hn_RWO~JED;e z8KYa&B)%pp@Yuh*uH2DrEE9OX7FpbR({#+YM}{oW^RRXr020+n2Im*_wboZ|;$X?kq&hmJsUsdCj4pOJiW0kx;VqA~T^s4w;7ZIy1>xL^p; z+YB#zG*bvuleH!iv#v|pDa~Kt_sy4IFmW>_#htJ`J$64RnX>+1an~hKDHQQiPK?J( zLri5g4-3`xRK$#n7}8smjVAVvjioT?kRX?LsqIVr26_>M)Be`m9Og`v~-spo=z`CoZ$!s-s~S?_U@jzK%&2B!t>_9EaL z(+M4~Qy>*@n9zKcR(&=wS>?Elj;RFY-X)Yu2FJTLAS#p3yz5B8>jk2De@sIerbM zb2gx|=QTV<10PEX`@uhPn-(r!n3W?jJ>oi<;)!={@*XzW;i`=iM=YQrfGzj*MLm{7 z3u|l+R$wyF_i+)pJ_DxxAf3pocFu5?LfB)tJkG1DW;`Pa7EDa=OpYF4gU3rxvJIA{ z!q!MIb_2Df#izTy(RT1;fhSZx%A?5_hsPr+*nqDsDb=jy&lB~w#O`;(X)8+Gg@Y3m zMG$y*`eNKl0PNzCuz11ktnjt%KG(i()ZNa5v4QjU=)woYVCI|<+<=+EQ6x|riCzNrs%`8IJ)=Y=J>V3j89y-{-W>6R2&?= zpjzFd4`$i3C%@Wl_oDDAl8xqbf&~WM)FNeS{TYYQJjYc4!Ml ze^_jjso;6+lYI&;_RWlMF_1kRQZ*|c5T`>&C*=jXbgiB9M3>+zaSz)umu5sm{Hvv?xd=brSp zR?JIQ8ZRdUy}F}rG#wWUBsA9e?tesg&z9uKyO+?kvw)C+IGBWoTno7FCk27qItPea zYfYlRNPjmM1TZB4@n=yL1v3U{vGQfv$K|2ft*duigJy-iASRQV0 zhc$9H+q#|g=t0~k^Nh?^1sg_za0#*f7dNh^{b2lc!!2=0sV-X>)N;z7FMs7dJ1|w0 zaGLZ(+3e?Egr2u34_6NLYf-JsUIVT(tqPd#qoK|~07b4^1$a0V9?2Y-lHZZKl+Zh< zM@^ZLgVltMg*meuD`4G*VGut&DQRcfZ55n0A4qTBq!uok$r0~q=E^$}90qx(Zwe7^ zkt`h{lNzN@o*W*m3d0W4$~A0Ej}j}GLD3V64jDL>5>o^&u~2Rl!O|xG>LWvMfRWsK zS`W*tRwf0%$LDhkdRZfu74Zf+J`}XH6u(lNDfH}QlG|>de?p$m#J|@)gtCNM4l6ua z%a6GWV3S7a5kZ%cz`O1cG@#?s%t*vS(Jnh<{ZUfCrNQe(HQ}+79KpjC(xokE%&2S5(i+0v<~_)s$<3b zuO;wX?w^O8KS2jKtTp+A*Cp5z9|&l;y#_vX9k4g+{e3SmHSi-d-nkda(c~&!9pbr_k5_ zWPh>M?~FdS-4ieu0BYCV)f1a;ImNGhSZkROl|$gaw{3h4@78(Kx;J4edT-OTsLbD~O#&#%9=`vT+)1M08;%6( zU%3DgYNRlRk@B_O>%B&uV0abXeP1FT&wD-94#2)2Oxk-;#6Ocp2nf=G)2)45%jRp! z$R&ydu%-Pa8W2=J)^n=zIq!Scsy)YTcCy1mwFkYv@ST_i*?_|>cLKV_K%m$UG{i%c zhncG%1AOtaX3W^C5KYt%_zb4Vn!CQC753}-u^I-x@{)FWF&z43b#hQ$oo`Ke`+2sJ zm|mLThtff#>dQ6gfL3f^`-R=F(->I#Pdh8r5gKaSbcRn;cc5FlMC zV)$-=-g%`yxz@|l?DpqVIkIU`QNtjlSbkeR$g>1h;rx?t!5=f^-1mcO^S)r=W`ig7 z3(W!1MMS&%-gbCm_-C1J@ciAI(E3uJIVNMk1u|gxk?)nGV$Ks3F99A)MCRD!dh$hFS7wCu%XqC9eT>3r1srxnK^%yi45a%fT9E-#kYXy^ z=R{0}MeSSxNG#3|0sAxT6Yqou`8s`*ErlZO5UQ`M7xRN#BbeB%z8T#Ghuw^40bVQwbJx4Wow36l3TI3c3^Y0yq2Qo++qQqZqB_1Em>>9(Dllz!jp0HslMvla1Ko%alTT%G+%W zC?sn%9}xwPX*c{%G!_)(ve-8E!4}>jQO^jlo&VD&tIt@U(voR@K6SPy$o=dLXZ_~} z%{*b=2MqSHt$xQnMytw%PK376P$}E!hq9pQ;f3BXxM*!KH+h&thMC|QE%}lx zOH&|&#jO&RyqstZK4AQ_CB8ynUNoFg>umFzEZ=1+?XWgkczDqvpS^dsfIEFOcsLlP zVIFK`;`9TW^pSh%vI3wnUA}^?Vsr;tQ4Pw*k@2*wIb%5Ds5XUTy~cRG(HmS#Y^bt}TaXQ>|T zKc&De5)8VlkvzTAMU}jpS4FAGI;dW+WMYR0SNn+_2Ntv{6PcTK9u6nl5HCERk!13X*TYE(JsQdktpzBtZztC#M>Y_X(X9e*~x(3nb z%p|1=Fs!_*q1mTOCJ-&@Nvu_aeAnj2eZE8nQAM)^S>dLJ0Yqs`AwMt;T8~H!XPi zD0>eb2Tx=QipJO9E!!Z+Mk;UL!IfW;RtB?_u95sG9@en1TgnOKT!CXdImz$}RCnN0 zsBw2>shUXUvC5bTja}R@Tz0^Ybqzj+8EoEPB;eb$QfoEqm{4Eg{#to#ifw&HnVZ%O z9pYV8g;#^(Z9mHA-x@mm4oA*RH{vlbaswmKh*SuxUc(_RI1mZb06**3|1&SBfn$_^ zi#NXgQA;M{BUJp>^few*MRd~Ays*g=VbU2LGT4F~c8A*_FyS_Skrn)v?}d*koG~CW z4;hU^!xjR|EJQR#sajxP(S^tP@-d&)ui+g?O*;<3riCV zE^z2eqAkf#@5COAD51*skY5*}p73r!$UvQzDgN_^H2rRwRo}BaA5nn< z?t8aa`QOhHAJhp2_$l^apqy88V_sTLlE^+dCdVJ2ZX2WOw3^(AxdG2ajZ}%D2fG5^ zTW?Dp9-w2%KfFo#LwbND$TN@o+6&}TW@3xhuhHckyWn&b;h1(a^?_(a0t-@C{75i8 zGbQcrfB_oJ1WG@0k!dX8(V3gh3kA?$gQRauo2S)sm@^kb7Q7&zkvnRD;rYDcJ=7q} z>Cn@U$*dlQGKTE4_TbQ3K1{sKKD5&Kh+NdcI!+j&=S^>-HS*6)x_?WtwUq=aVE0fNH ze?nzK%qdnghPlm!)@{O5o{|SeAbO&vLfz3f7F1p6(YbU$+pd5?dAPQPtw-;JZnqZYie3ztYza;1}85xTg?5Uf>qL4Pg zD+crr33$2Xa|2!`UK!KYpN~!R$7QhnM%ybct8d*)G(X2EH~RbWW$=5*+?JZ>@UtL1 zoXVjp$oYcFGU|B$6y!7F%B_6OnQdZ7*jQ;g!HLs~OZo%&a*x|lSCd3MUb4ppa^7Q{ zGAW1G?7sq%9o4y=EbE8b;5__SnucRiF-u4Q-WPT-8#i04sDo#SUnW&3&|(tLUn1R_QY zZV2c4q1F6jRY*vZ)@H(0w5RLw*+ztl81MNp%NMR=#vj=JV1GtC>bEbeoalSUsMPi_ zmi209o|V7&8XuAtlRoc1@Tm3&na~c@Xi0{orybE$fuiT`3`@ZWR%tqgP^`it5$3^u zSS>)U4apn>JP#pZ*L>3QjJGE_XPUj{!UF_}!#ih6;&&Bof6G8soFsj^VT+W~1ciVi z1+C*IJyCiw+#qxvJ0DpvnpUwO1%Xbpd?ASJgz(4yJ!k+auUe_pvh)WpYi>r0n3=rN%QR2wD z_E#cVOt?_G7Jqt#x)A zFsQ^snu}|@Mn=&`An&|Jsfz}1i2K?Glf=`3S&RDnFUEM_$2Okb(($b_6(e2Tx@ijM zL)gP2VZ?eTXm{g!felYNF}O8Nqii(=F#tTo^~t3}r3~iKKP=|=uwsd|P~g@*b<$Bv zcnjh$?DzP5!&;Xk`2CU{Ms#TOQm1%B#~h$rL9!;}+CM*XU? z-622M69fM@QCvQdqxAIm_P-wDISO5cCPVVW^lR+@XZE0pR+9v3vD7jML%L2q&~Nvn z>!B5y5!O6bo%zoNx2t`LA>EVzaG;<rH z5l7mC{5E*WpL-YFzVU~sSE7VpKueN%+a0hVU0sIjv-RHYS){6=^qH<=t0f@BO$gt9 zV-(Gvu(-FGPm~#id1;T7V@(Q&Efw@@xn5?aD<=OMA)1Pw3(s}zZ}6N!VL9k1}#UABv7^!UCt?8_;S zD7X)X^IsKjY6QYgXIqKrks8{Ly+3KUkcxr4NrmPEYx+z`IxN3MqR3Gv_+0YDc%}n+Ri#?FoUu3;)RKHnBD=n$FfQ1YdPcBV z@yGnyWBD+?Kgb>lp*(1$l4@L#3`lQ;1L06@RC`=3)*|d7Y*_ zAZ;)}^+AT$I3xD9`xw2!%hnf|35XN`*<~NaMrX898~K+N^BIPQSuyj6CYA0hB7Jks z06z5U8CTY^D^<5Udz5kkRGnBB-Qg73K+Uu-&l+ntKz;>gJn(Zwkomm?Gq6=aA{9C< z6jPz@pn1D#MePe4oCc%!N0leds?krY-0HR;IaU?XuY0luSyo)GfTbmX8KeQE+KJHl z+zP+h8^Nm<{%DRATW4mraF|TQJpJ6;$)ZHTRgmvr7dF$#gC_o~tomOCJ-dFAZ|~q- zs|{<4N*9mmMARk^+KW<%`Pt0^Q{aFKrpjCdZ=dtn9X~a+n$%pg@4tP$1#X;;m?9)C zsIu`UMk8aMAj#L*&}tsvf56%*hPVR3AdJtS0uAozx&y7^m^_Z{K6burS6btBgz+qZ z7+m&$T}VFpIxlydO)%Y^yGI!iD8vOn&uw&zpA$`E6w|##48AnShDW8v$u!BsH$x>&;JPbT2SRUlo6E5z zoqC0%rIjn3=2i^F&Jlu_R=Ik0BiX91o9@7fcr>YK0Mnh3c!V^=LK!*S9-5z2@ra!o zsXVZ09!eU4s(Hne+ri?xnUw_nrSYT3eb^96BkKrRF+TnGU~APO7_Nu003`ypQfPb+I$ znryO^*#W=A$j0O|&*5h4?YQ@5z26&5^#!~$K^qyd^mBi|=+6a5AKjOH!LUTkg&&A` zJeqg7a}Q!37{7G?{2~*3JiB#WZ47LQjXTaE-62#Gh{qAq{rNMrtc8TrqehTHy+|Ed zWAS$tR?sPv)ytTSPKo(#eKGSVZtps&3-y8K zuAl$U3jm&4FX4K_yzEEg+VOQft(zk2WZPw;HqKCT7@d)Ae+PFzqUB(fe=`%9c_Q`G z)VmxP8mn!6>3wHG1#e2Dj_0UrA9O&WW3z{fbW>Zk&O*Na%YylLCK%_Z4OGLvd~L_g z1XDO$R>S2dZG5Ei(EcdmrztImPuG3((#EtHez>6oA6D3pg?g-)ziY%a^0$8+qB*iu zBQ|l(M6UtzDAZ(VKUrYP+0tBkG-jj2*Qlwk-%K^cOGc#25!oJl^yC%b))wXJdg&y=m;02Us zI3rf8NmYy5A~<3NB9(K<+5I&k$H$=c zG~;_Wy{Xp=qqV|(7|%`X^V_9fY#OWWPN`DEqw7bGzz2b`(7BwXJW(JQ06PVhB>gr5 zz;w5Y*xR_IUqs(LwKy=`zKJlpk^I=l0qg0`<9%V{Q{&M(3Gk5_k4rrx_@|2;bw^o zP=mY60V_XX8lWs&NM3-H4|>*BWHL{POS5|kVBF|Nq*$7vUk&i_22-&Mpz z{|6YV9Wr)bg_G!OjWrn_mQrEGi=(HbbwPeuHF2O}hE zTzJgD00lPWzRs)d_IAxqX|bftmUdX?$E(xZqRyptuVRJCM9hmGe9g>^l9d-w>t5~9 z^wWLwJO=kJ^hLr#&USw|i!Z%!v?f{$Ig3ZzIS9w$xIh>r-7&TZ4bp zO#<8Dcv>5dmgrW_=qR}|{Eo3Fo$fmH?L1w$ijGb>7J^Qwt<|Wz_A2qX`dpK#nkT${ z$2C$&So<_O_#%o>bVuX@!UL!oZiRnuVU4vMGH}9{Lq|8Y%RRMMNZtt+|2XV&A8Gkh ze=@oD2acs`+3(+)FN8@ZUpNkP{HvOHf9>kEKag^`x1Sk5-&qb%;ubv&NNa}(lHnxR zI?>b3S8EzMe~ByFk>Lh9{_f_?fYzirRc`zp4>vyB*RG~j=aJl?G%1(CE@q3KsCMYY zpf0@`KbQnYw=^!?SWgGh$+>8XZEgK&m!D46PJsL~A+Myu3icAxX(Hz-Ee?HA_5piK z#OcYphp7?2lORz}i_S88Q-_2Lbh)VH?uT`667=cGrbDq2t^ zca>B`oF-}-B5mxO69P!Ps`PKu?px`fMuhEVHClC=>6R#9#|Ks(I`Fy~bWJGzMQkFvDC7;{u}<~2uOg)KXI9ua6j>|6sxfp(p(X(DT4@`2k)12b@7WrW ziOg~qYDE6l7YfHUaVdqzc8Yz&j9~5(0ZC31c5sE!Ph%zxbb&bgx2_;AIckp4%X;!s z(1LpjwST(tnIVGmd&iJGsWgKzrO=Men@o^4B0t2J`V;2&HY*I-^(pJ4kGFFWM11^m=R){BQ3wukX-cotd+s%q@CaC3LL_|$hC(-o>ug{7-f`qW}_OJ)2$a43<;qS2x_!!U8b zDcWxKONk!517DiD{oZMLlOQ zH`x{y`^4~j^|uJXcY1+QcG?Gdl@ht2j+YVdP|dxrn^8QZr%mUF>bsySr`ZmiYWxg9 zGzGx_?Nkof=kW59)9;8W+(+hceXd~D-EuN-VWWRaTh`YqcExed$`c;Akf zLE@Yww%&@}(nYUcIwerG0m&(<$b^yC%%mzK*sRmRsmp;x{&txipiCFd8lwY5!}A(r z3JAO?$#3cca%;QWIm<2ulRYhHRp^RIp3}FW84if`c0O!cV!QF~lQ79oeO&n0Xgs;N zVv<)wBV5+JRK`Dc`5kv|1$nj{;Aym##qgWIe!652Y9lW1GjQKn$j(2qCf$+r2Biua zGYvfy96#;o4w?D8_awUZ_Z!AbgL%O9DL6mMbEiEnGx#?~sq`SLA zNs;bmOP6%)cPr=I&);)<-tW(N##)21KdiyJu50$3zd2WnWC0tlG*+ge+xfwGkYWV0 z0IhGeeJic6i#{7Z-{$HA#a`>fH2qRNcvD(v z)+r$Kk^)%&_`6pXL-Lry)~&CtS1``I{F;!0^x9DkIJ{`5h1!S%i-k>FOGBEvdzB?F z!NB9?vOx9kPQaGhl09bf^(GyD{^Rm$J zt;;fI&}Vn#_ENhSAsO?!9*E(!b>tcwaT0I+ma(iBLo%ugrZ$MlCDr4GPZr~ud{<39 zBpQ{H)}v~R5xOURi!JO%7NiZu*_~~5(xI!EHeF%cO8bc$IzN+5?}P7BsFCm>~Ugqs+H`x=$ zu%A9NQ0c`+S|1SoH!pzYOA=|hOh0iRzv(x8i3T@K!v%>pR=SAIaPuD!=Xnn#TM5hn z+@X_5FN^D!_Zw8$VknoD+Fk}3JB2BJz+x%Ct<8aB;=skhz8*e=lL&H_%fD@?vsNxc z713E0D18>7i@0}F&rt1@Z4Tl zV{Om3^NUQK@G7tI08JVXPjfe>$l8r_&Pn9QqL#(>(#D~(qu9D&sG{Ft79O!Z?;T=nxrAKF zpuP{Qt>#|}4Bu;(*5x_0sp{YbF52{&4a!0+g!xrU|O>|cWAGtAT=NH>s=p){Dh0QZ!VIN*5t9i1MASd*Ic39%) zaHjCRa_a6n6$a|S8PZa6T9rR^Zsv`Y3-5QCe@fpyp{!@xOxfMsi)~a5d2vC?CfV3b zJ~|vS>8UU-XbkzlAR71;5`Zn8cE^HF!uuMWD;N*V!-5I>M-4-ior?$qc9(Xe`X~_`K^KO*S>YpQL;WM;tG%spD4xO^Mw4mn<>$ts zUN-L5>7Hl9FUf6gD%F>8RiPRo>BdWq98t53yh|TS7gHt|rXCqfwQU!d&WV;Bzo9*( zP!PF_(v?(MD^qWLWYab~7M`kpCGvA+@j6{<&2h`r>BM-s^Qh2NR{5@MJ^WCORO8N; zmFeyEa)D?)4b~9iwSxB(lOm59o?^5pRU0o;33>mw=s?Q1t=_6?pU!4DK0hyHQ%Mi_ zc=nx-M(4_0Nv~?hVocKsz~C&ZGGOK87k5|&k1*-*dUL(%MF{PhVBN66h*b)iZj{-; z)29+O&>=%}ZYSr2B4K8_f>bKl zws~4~sS@l#-Q#VDe6xUsvzHz(v$E7rPsk#s`?aykbwgGg{OUkgV^PsuzVR9FbQ`NE za}_>9AFp{R@39triR--@EhPG;8^BTA;J>nEK z)9{)WRk`w&S5rz-Ay^UfAdNdk8|_FhJAdA)zhImy#8ZiJ3)+OQ) zD`Sh!H|8U)VPF&-YLwU!_DezmRgJFVWYA9gR-mS(+a~2^|MXWHq01C2o9NTH%Vy70 zQ2zMheu$rujEQgB>3Tpg`TNwT)47sIwNQ7Acv{#fqApYd?eKS8qt(;4hbgo(7qda< zhBi)RZPym&`qNheMGbea#l4}bkZI(qaHS9}j)YUXnFJAX z8jEn6FzkwR3rhI*_twk3@-w?QpZ5yn*s+)QWgfc9CxC8MZ+(@^*1KKHf2n-`qtzo3 zpZx4hQpl?gUqptEM<4UGeiH`4{Zg~-`s6z!Q(35JO&Q`9_svN2 z!E|wlGcD+#SP86G^+_K zaAf*=^hcb%0$Lo&v)C`dtOU>QphH~kllKR`@ssP3H+9fvZE-pZcrc8<#489Lzo|>U z(w#V|hUn?E8yOYPt$20$lT0RD6Kg+OCPUFvq_>(F0mg_5C~_%reiLzccqAevcg-%l zHudzzoGhqGsFHp4Dzpd}(4LVw2wtUy41^45Y6@45x*rl^)j3(th}YcH+VzcU<|N2`N7u`tQ` zpIa;vl?I(OhXqs|it+xqwsOiD&E>qIYRDV$CG75q`AzV8HyjGcXhCN>Z_(uLe3w!= zdPh-sWuJbK6-6I!y(reM%>m+6`|f%*tAR+{ad`3bzWOCsuhk48EJG1*t8;{oSx{iShqY~$AH`79ohHgeiB}A5o9NVSH!;ThmxzV6OPyU64=LfJY{Dg;pT;TyXn<%C2W&D`uV6dZ2N020x!;8;y z5Zsl!=jySzm{=wjZi7*ZFg*7^Z8cs*tezqkm zc>Iu*thJnmr1wLW6j)xoa2GO2RWk&Q+Y4ayEA*3_4GDb>a_1xSJv~(xg_|V*wPr%J zs?Copu&W{@+8w%jqfjA?>2=x#I^7@kfN2R43NiRPOp2STVA@ggzCkAX_1cR!b70sC zTdwt~bafK^iCJ0upCqdO;2WV*rsyYtcj`;ZY1nSjUaSMzlt1T;x)~%mV|xO{H}Bf& z!~zYwNAP+fI94u8DUR>HH22hr#6GHJ4>)t5v=`%iw}pQzmR;+#X5n8h8|8JlTqf}bKYvQ{+{GAy1FZpkkc1_jx+-(Jpd zJJll;*DG}3dYN4i0K+c8<(I@l$zCzXm$p|q1Xod!=vYf^-jqDVyy%(rm8@RcwB$={ zoR2=XJ3Oaag*+2g*j!qHn2ly)c18OjzWj8E^45D_a7yIab{%ofhwU(-^ozC8HQTEN z#@55zDib{G`I;N2GsvCn#D%bA zxqR3#^#*1_+Gxe#r|R83GMeQ&+l^c^bo}E1iynN0@f_`vk0fp}c}>=Y#5RelVJY3c%qg0 zj_wA8h%Q~`Wmnzi7jf5saUT3%ZWPzw4}$-nd+?sR zLpqnrV}izrCJ-Syi(#hfF)g<|nE=HjGhB#)x&s=Ka8GD(N$(QdboO^88qDpxyO@Uv za=D*=SLW{oQl(!(23Ydpe79rgv8a&H!`mu*VH=MO&%=zrZXz#}Cc&tN%rbM=`&gN` zxe0g)DfvwvA5q^~z+Y$sBN&P`;Eu5)uot5@7!@~)XcpTpA7J^OvC33ICWgj}&$qQX z5?()xl*_zO#?hEoQ$QCrluMO>qIBv06Jd`f;y)Dn|7dnNR74IRPh1dg;Be;*Hr>tS zj%=I^4Mm}R*nTLSRz^F#i`1t0g8V_M$wTs6l=EZ2Z>9gB`v3X2gB;~&DjadV01|Hh z>;gvImQC+!_ImKk)bJ1u)Rfn1h%-A9sTDUblSPmAP6gC|dj~h}9hG8#-zEA|gw zcp!?5;`N8;@nkO?bB4vm9Ih=l!m{D!4%XUd$7OW0ZezOg8=W!xV!@O6fU%`6>T z<^2cQvi^Yq)HITt^K-siTcES+oiD==t{ETEN6Ej_kY>dO(f5V7O7VxRCIJ##+dQcT zBF1+gK*+KKjCbKKzUr2KFKTh@k*iM)c67cZ`g8GLuFvdA`Sy$sAHi~Et zNabGYzhjy9LGjVpzss!{z*B<48)*j7NG{2LhHlgPQzc-NJ|e5B4#*NL`9c~)`g8s3 z>Z??>tdhE~HlHp`q#jtPl|Lbg;J+QpAuftGd>t+jwR;P+hmwk-W&a-6i4^q>)5CJS z=D?&aIEv-;bzQdyE7|j4{WwVJZ6dg_ZK4)_^jZA zB$T2{-FxU>d8t4Q2d9LdBdaZMPd%`L--nmgul{}xSjvdL>fZ8-fIYd#72@35f;@o$ zOBp&Ln1TA6Vx(CSMf6qmeiA;?Q#0N__fl;`|Mc9wiQ*{JcG`kF3vS+mA^E?oGRhkh z0aXoW9W*<;j>Ye7>pA%58$D zq!fG4@K)(vpb5TA(A!uyc;ji!8ZYF5fq`$|7JMrTjL-*C0)O_@H8Au>oTa{lh!1ib zJX)K2a6p3%6CCOOrqn6mnXrF|{?aPmkIcr0gm)?L9awl1}A{symqJ**|Z5z=QQVz;%_^BT{*027{8g8TEkkq~Q z;#nvD$LBLRHa%`|w~k-pW!6it<^)&ZKqGDP_+(HE3?Em(PwJE~|CeKr_q%Xxo(~26!91{bD}bf9bNz4O672|LD?aQ;lynz{^rK;mvdd3b-OlK{pV!mh zHT0Db!2)C(ER-imz`HdX#aK;}Dy?Iw=ekh#kyR4R|KP|LYM9sxzVRd;{C%v4^$4-} z_7tCLZoLYOuaf(Ar6 z&X(o@G& zH3AmAIHTO&20oS}8b_%Cl(U8Vskd?d^R2MoKf}DCC>7X+FJaSSpN0%@GIQd=%u!Zu z-q+%(fL@HwiZOn|q=JbjO7BY;q*gl@8H$Uz)1Q>-JS^%%_|}S*ywMA^5f3@kik)NC zIzfQmJ?oeaajN}sJ-gjCf0JivY3b$9a)nPPm)Py4Y)sOCPH75AAS1e9u`b%DR46Ze zf4%g%8SXG(4;Px~-vWTv%^WK6F^By@;-*&}n20kUXmU3}mQ$c0y5CN&3It$jIp+{I zD(m=i_ru%hpyByb?2@{Q2gMmwIfBqmi^Tx2lv8Bff==HJD5?$9yq&U{PiPDD9k#ej zU}D-z5i>GE?CPd|tEGj8J@ym;?#Mk(Ggu_K%xYA}oE#2_t~MVO&zp8HbECnmzhra_lIWJy6 zPifz?`3pj~7SLSfgB>4N$JnYv425&+s}=2C*&|uRr$;-jJkK0;-2)!u3wqu26F&do zEg^(`m%ys!6B_zB=v3%P7=Amp++!c7r?2NzLjz)F$^FDdK$X8P?YCvXo^yFY*X+0z zuz{^D+PmDT@#CxANgx;3AI>j|C*Y2*gAP5_uaa7>cw1F1TZjt&mDS-@I$A~a%S=wp zr&bzx)>`3f1A!}t9QnY9$S*w*0rM^n=3){&BS0Len9$R~lI-hSzlC}tX04hxRaUuc zUF;mbRgHo~7X*8#x$i6X^zdB=d!z!Dp?KImP90~pmw@ch3GFsb? zG;_tZdz3zCDUvCwNf6GPki0bMzT^u0)8p!V^=TP#reNY(65q&{)2HWNOc(^DGLmza zaznD;as_cgq$PUbdj0Wx!_HZW^qPSOc{TqCLuR1pL9dPZtSo`qIaXcj9v%pxk>vd{ zRt9RW7G$RRBedLGlKigk5oz~yDatxNU6bGNk;uQVtBrWe*pHV9-tqROk z3L3g{j1rRQ)*4eL@Kr*l`l-B>f-_I$G2$41>6g#*sZ9v6(d%`G_i;F(qdrRvXDSwv ze(^Y}F;d+=`SJS_RNFV!q6wGzI!fXG`osIihmjpVpE;6TWEuyG?cwVL&kmn>=9s2O z9z*m#&ns%!pPAsu12y!lxqPzo>@lbQwBaS3-$p6%OT#@nV>L>*tX=aHK`kgj} zI)(i@TQj!+si4cy@}gBpbZ4OJZ3{mRvRcm%)2POqiFMrdcAfAf_?-;3$i&3~V=?2b zoY9Fdm#T6tg|ec{G$VD1R--)jB3pO&K+vcXVDHQduoslsw^E8|YaRPU;mKoW^`i>E!!Lr?(5F?^GP{@D z+_ep+of7Zgzb!VpP$U#+Cc|x4o6JaUN>^i(6CVjzAxs*tBvJFkmY5)NwcbND7USdihGfNTYw{x$NNczRydv@BCfLRPNAN`i0M#P%HBf;n`gI*$VhMO z%Gc|F8RVu2U0N}960PuBl$mMWX+6I`va`87(oeGAf<+U$Cnr+Ru|aHVzzSPnmG^%5 zvFQ0OH=$z)`2~=CYy`f$smJIk zMs5+@%7LIW-wBKt)^3)dlVO#YnX_IZAY_{Qm9flBWzh!s8_b~f<952_;{N~0z4%yT z{f<(tS_wei(LBZ?fnQ4+0=s9bY(N~w^r#`p zm-7V|d)q}vwRwdQsWl%2YzQAzJ{)rlvMh0(~w9c!&Z3u#^|D0FurIaA1K zbjYe#8a!FL9c^~?8c9oT*zVi?=?PY($ne-wnDL^}Bfpr+jN6kAyD#kRVXZMS zICyw?O)N@%mBHWxiQ){`I(Uts?&F?H@3F6gu<@5MERw`!RY-VxW;_$ zm%-hUlp`Sliv`iiC`x72x#2e#5W@^t;1^8B4EGKqV<~CrA|BqHA3r!qm_!cJTDyHJav#Yx*DCfqT-@4zkt2oK>Nj_n zMs6a_u2cN|hx_Yc;=>Ygi7L7_023i<#W7ZYQWLUa6Qqd4V&@z$<8+X zcpCyCEm4M5`@<~SY?1DlQx8GAQ>4<0H|GOPti7KTbw5Q)`Ma)k_SdTa{5c*;kvAOQ znZj*xJhuz2%-`Nm7nd#JYn3lyKPh9y=nl+}ov68|8@ddTr$kO^q+9HZCqcantlF4DvrX!G%A+o%aM6e4J#Z)h+k9 z;!k510u9!nc{NjYyb<*%S}dAtM5!Fny&scJ>{?o=9_jg(wLS7`ufOP8y$lE^sG?hT zO@~OJ=MEo(gZnMlGYa-y*$Y9G5`Nr1{k0y{IrHh4rlTcbLF#z4K#gjX_nkFjsQJm% zfsSAFZz6PNvhI`pChVt5xU~ChEX})$R4lYZ`>Sc?w?5dbV%(G=sw)_)sH*DEp5SYW z@tD$#CZe$>mGh^J65mkam0xd+V{C`*^7F4#rfJ1hv~W8Mp6?HGv7YVJHLrV3Ak`AO zh09B_E@EeuY7gVby19o{MTL{jgt2&44u9v+OT5E|OzGb`@{B2Gh!-Ee5tmS5*b>!v zbe9toTJ2?vej@VTtBen#PlEXl4J3aRz3(zL4X`Y-J3A>pR0Rc_7yG9V1Ps`-)r%g6 z3D~{qK!~A%s3QKU0H@%G;etV4U1P4Tl&L^!Ovpp&3#n-hj6$f!YTIKesrD21z6&kTkIa)Ba=HZj0W!xPrZ-DRy)AE z;*i`CP}azLy|{7ja+7{BHZybIy)yAE_QRZ+p+l7k{zXF-AVOuT+F+4Uyl35c>8e9~ zg~U0$n{95;E-fJv%H|jk~l@U+W=2_TiKdEY@$f87A_ukSEU=?L^ z7a~=u-u2abNi~1jc|pTn7P2{KI^a6#Qd#!JADDKNWEEOj?JcnJ^O4+DCG0m7G*VGU zVcRX|UNO-B;3(F?1YQ-fOF`Eig**Svm(Q$765etBN8dk_=VWJlXx0~p;oz**elu@# zI-j+ViWZTCp{wF)Elgcr&T)<#R$LZ{;OvP^nZ1oIxZYJtwBX#&8qaF1Ih6`le za_G&sx|P?B)adQ?MT~jAVg&5Uke4g&SBHncinU|czcnLewpw3bkK4SGYVxGAW>tNW z*MJ$#?zm%Ao1|N}#5=8X%cJKpiN7QA#A2PM#A-A5^OHV)NZRL9dmu>a8$K8m{X!v~ zar%r)n>Ee0&!LxHDY4f2?ol%_%2VP%h1sGVB4*td<$jKP7=$q3<>!U{x!Qid&5B7t z$+hjv9cJ-{meT`dQs!t<9LLj7&FjnjIxe0Kx_sr5jg&{y?A%4ghsMUojNtubzq;U7 zdZaUaD^Iy00-e3o-Ejgy$?T?gqrh&R^s0?bf2zX&@<>yE<=lmv47o!Gtk53U+6PN) zrSVtH?kO8gU!N7cTa&Fode9+Zrr0lm!cOgrn$}k*Dg#{ye%6?0r;}8=%gSJvWus-_04 z3546-Ny)vS`ING|XMSyG`ap9;d!3d|`t2b=NyS4r_3g}TEf8+I6pqPQ5E&b*H?wkM zHT*SPj@(xnV3bx_-Zw!lv%#NN@P)E)N@Y)$+`K|`Zi%_*i1V4INpP06DyJLUwhVJv z6)*6aM8-t4!*{#mjIT88O}3p_xI@OJi9#-}AiM7h+>40BuQ!Xzz2r5JWInw>ZH#%d zBk-J>)E<&in8T0OAG5_-i=x&7mTEwMt@X9rl9u`DD*WnRi zW8yYoJNI|8NUyI5g(UJByee=JTYqyFa_`^Lg0M)|hixufqm3qw_O_i1>)bX?2qSr+$CQ05ov38HF zeP5WF=I!%lN_Kw@=L3wepG($HI3`sV7j?L_0S(2_G%i#9%cCregq*Dw5ydvUVKDfW z9?YHX6)n9ijCa#?-+Rnk=^bwsYbWzzgx@}1&^HOA49)0WIi)NiuWxW?6`#6zr+)Kh zsqOHhD)0zrP`9$>Oy$SHW#To1WztVS*<2>DlOcz&y|C8Ajl==;8TfXX2kd^zecIL_ z$PaDA-B+#H@ziN$M{?XjrnT{FB=w-|5SZRIT`udHu&pDnZA3}rA|?Bywj*|df|v(q zq3d5PKn??ocJk!-^dZbL7S6W}!4BISs_( z#!jRAoj7)y5`1E>a(Bv6=(IxTHMLddF=O-Q2sPgzTCa%7}X7z92h-xqpcI`0|HjiK$U+E21 zy6xE_7xIUF-n>(YTNl_H(_86EBviY+$Sr~ASU1AGW1!8eu*l0svNbfD4#xy};#Dub zbWk@^hDNjB2+1h*_$iQ&&2e5mIyJAu!l!pQxPB1fWlyT2#PLxU;d|bsA?OV?)tcNW z8*QHTM^PVBu;j=OVhM6*2mqDNSeVzG+m@>t=L7Ip4D$fZM9;gQ4_v0Ubc!_ z9g5y(MT3MPe`L}GXt9z2%mz^+hOC@DSW>7Jsqt{dZ3K=e`+$-vZxuA#^v7KR4G#qn z&L2`FE*q;zSZG|ROsZv_sWxrJ7tPoGd!AxF+Nd$@{;=;ktZXJiOD}})LLQ^`I>#b| zOiG5GSL&KHZ}*K*i!`v?mSTS>8J~I;5x|7Q0Ji`l&!O1#ZyZ{=;oj5bPeBmQ# zFP{Q`q+%frK|VT8+~*Dq{>6b)(**Mn?*ZM(=WoZ6vYr zS03e%iQa)Zk2?ZVq|3_&zA(k1UYT-cZ4<<=kj0CHANO1%XZ>~b>&rSGQeo-WIkNsW zjlCjy!0ovmlW11t3j|K@O}*4ri+j7;hUNJP@J%CAb^Br8DS61XLdV(Xhq4l3 zg=oXoqgJeF5^^=BIMJgHs`Z%ZdF4&&(=6n}sWN2Aw^zH%x~gEj-ZjB#FD1xWw(>9} z!)+|b4WZJd)dD0?72li1kH^cs=CejUps0g~dXXgv2>sE03QU)btD1|^Gnf*M_qW@u zuVl)i2UyNMr~P)@QwOIAPN{7^Vdb7|S{eiJ{!US61CJFA!m8osiO+cF=14uI=d$>@ z*w1#C$Ag}5tNaFMF1$|-wCvfo+YTMM^ymqOo!gg`kp06ldH16JD*5JVKQfxteuQVK z;e&%&Y!W~l);;m6+wp=MXf0*!ljAi|acL=+E;KOJif^v6w|~W2YJ|}GFGx+_Z{-UyR2= zdkaPDP=T=4(DC|3cKZKs$NZl3g3eYM4Eq`(_@hp<_Q+(S!!JqJ?1Ir zt~xijAb1*|)UeULY2KpTEC<1|2?<;e(bw8M&CTQ<1&YvOmr=2Dmx;0O<+5fVXBd=X;Nvli`MP?_(-K#yOw8;~)&EsbEs@Q+tB+GPEt2i$*~JtOqcc=BSRdUHjFgW)pQMh9ysQzPh5+oYL3(UZ&%>OOHV#8v+r zME1|R=MpZg{H{6-0n5ut2W!Gf`d+t1%!tQE6_#rHe7~E2tGM{7ZKm+4yX;_LA%jG< z{BlJtD-A}n=}4#8JoW&Z)7l4H4k8t&=vO%$PTF+nY*qn{#c#DIj|UC4zI!h{peKg? zF3OrcBi>PS?dKa&mW8L*F|6jkODFf)Hpk9R`tiPX;My=!co%f%G|XG}mMK27c$}xG z_v1k$M4y{>{v1h2SojGV!9tcKMe6318mvYH`xM$PV-FMeNo9?`4iMC<$ZV!et=P|_ zKOt2su$z~H<$h)W=!(;IHBj^Slx|>D8j{8Su|Lr+b&vsF;`% zSZ-=@(B%g6he!1nM&nYY191#;R>@q=4moWWnnI*28a`Ot+p*^Li-k};;2f}$q=Z?c zm)7qHSZqYy)8B8lwU)g)7_PVN8D|k4jh!UyM)y4^ce`Ng`l*?5F>DqxEE3=B)()UM zqaK>KX)h;$ey4X`RZ!^js%hdK^=ufnQ(4Rl$dp}c-#_h|;)DtPQq1Zn>l@jq!P(=0GsHqK&@qMa7(*>59 z8yJdBpb-lte7L8k&`_AJRHO#AIWo>A4EGDc1DbHFk~oWb2^Or8uf=6bD~PKKds&WE zn|EeYk;(%ln(ofE&SZbst?fGl4X;k(F*LN@_EnO~fveFJUBl43I~DgUW0}lUY*{0X zTxL-0T#qJotn``G{d7M@R^C1`!Fo$2x56>^NOFC%Zlpw~`KT&rE5KsNEd3(VCcI}0 zTB$M9$EWr0Spajy(?ftgO@eWM;j0hvLOs`xOF8tU1bZBu&T~yTAX-_4on_+NT#PLJ z)rOL?a z6FWC26Wgh)xtC|%UrUn5_icNZEsT_Nx9I3~ChdokEYn1+s)XfBaiVi3F`0Ri$DQUh zyyL6ac-8z>slS|x`Kr&$Vu?G4oP=1YvyHyBtyU(okK)_18@e|eJ~moznMo!|CBThc zUqTUn3N^T6R4ob=+bI;O{hW2VmxWi8<3Z}Cp4nF+gd>f9~Ssd#NCd805xxb^&$n33Hq>||FGCbta98Gmrg z-mm5z6<`T<-e@O<@#2&VL+`m`>N~dO>$Df@Ls;m`D-a5!GzoT|QRvY!^f<*2&A0hLIicEIoC*~g6MrRy-qVz( z(x!LqKzx&2)!jsvK|nPuh}`qL=VD9j=e&w#;ey41w`F&$k{ousbBHMR8+9JlhtdRz zl@QTNzDwJ%;@21uSeY-%UIHH{Q1DJO$KWeK=Z2ua3C}M4S)YN``K;g9f@d5Pm|Ev1 z@Kfm)us%7{`yxO{5ylq9=GHw6e5_5Gq>%yB!so>2i=|#R$FTzFnRaw^diSKWlYpU! zNT{Emo@X{@>lL+X2_(%Uq3*}?wZWX5K{j4WQD~H{tX6MIsgBgQ*pD~oo6iUchLhOu zYcQr_Mhr59xyB>tIo|eF%54)^D4`Ok?HCQ@X*I9OT=|}kPMW0?oL8Y$?1(tD(VjO~WNK$YKPR*+B(@Y|SgHzQ)oE1ZPn-@jP2~`|-`eBeP87w9%e380q9W z?NTU~H3qCMhc#&2%{bMN5YPQMmVVPAn2no}Ritd^0*Q!7fX`t1Yrqu}!H|r3Dy_}C zF^-Zehtg=ra!WUXdlh_+RoBfvqc+cbvHRN>arx6zd9D-9M{3i9QrA*W54l1Gzqhwtp%fD( zJtert#sj09o{3Zu`9e)@^6s4`(voKS1r>$x`01CP`_}vi-$UA`{j-Kql*V0B;~}t$ z)`y9Be(1|}R>#p1u$0bilu50(N-&O{#5;{2?7^?V#6W zQ? z>*9jr2Siz6{WAXq;)qSd(C+&JT@wP81 zKq$A$EIr&hz%|Z*$Z47N<=4VDguGIa{{R+yhrrNhxM5-owGSAPwIt(o1aODhXcw+D0JpyWrV`l>o9$&MFL6R?G zi3})4Q;dgZv@@79}Mtz|7i(q{D2y9vt{65`XjRaM@s-X z7OWuwp}-^gGd;ZBeHhV#%Q~u?V}`3SoT`nM92YlhR)RTKmeqjk% z8;F5mu5ZT29?!Ya@1JplpO$+j1*;{}t_Fe!ZM#3?3q(|-5PvzA@=oX2Vz3rqQ>$m0 znP&<|-?%rp^Skjhg2HyPeHyUdczVnnM))7FGXWTuug+fDlT_kYGfbkc+FIHeoEnwo zr+xx7km)gZ(me4G*m~)oc8_mHQf)|xaEg^&3qdY1OO9>4l5GFP#=ZQc1jC35N^LA- zTQ_q&P8|6%9$i}(R4Mg78)%iq2P*Oiazo}X3F|(vtCPpxH3-*b01DtSVLdyp-nb}}-$>qUQ|4xPK%a|1H-JZ(!&^ zNZ75wBczuWu(sYqul6?nn@@Ilpc^<&@IScm-(2cL25VEBm+-zzU)TYV%-dMOH?<$O z-?J`bfigXhFLa6q%Avau0TC8ZvwwK>{}zFlpR`~{}Hi^HeUtSf{@?v2j=X5b_Is~YOj=pE$EUS^5|U55!>SjSIsB@Q8L1{`YKqfz1V)wh%S-;l(iKM7vb{-Z?y zu=ff&So0eE(xEEB%8aK4+PAhA53cXy4(Br9P!A2c$P*{}jz9`T(cvq~z`oCd8_+lR z2A0fMp@0$ue6l~3=fl#xZGJTjvFK$&-oSsKgSDjIEYA}&KYxw~`?wv8xw(0zvkjS@ zz4J%8>uN18{}9~%T|OA72Q-!q`8GGV!y)gb?Lgm=k?u*yO6KX)Dtm<=R8hVL$Af1h zsbf!yq%QdM;BPNI{Pj{{!^{MbBYebueI4BX{xI!S2^zsY5mgV6j6W2H`0BG#3_0z= z#iSBpebZl9T;9LvEE;@${ixpTde>JF{yb)tz`*+2GT7+$VzC_LCDkT@zwO%rkNlso z&|l)(k&k#Q;~oA|>bl_7mzU_sR1)thjPYg7Qx6R=o!2y77X1JmEc#Y;YUiO znbiEaSLFa{W+v;DU4-j9W%#_`j>JrrBU{R%G|B?3o8p1uOG}M9*dW@`jSU)Y`{DRt z6wLk@OwkwO;#u`lXJ$gqfW6PutX&!sCRwm_@u;Hr{0(jk(o zjpgrj;M*}TbVr#X2=C;u_VO0AAm0>fv)LY0E?Xy{oCsrejK8wF0_uNnMQZ94#sN_W zf=-^sVo~y|{B926O{fwvo~KX#_qLtezS_}+b;s+qqnr65Qwj;mv8B<1ty%Qya76F6 zhj+9aw8$%_y>5umi8J7hd3MrRbUinpkO*$gg?i4_d~G=Dx)K;R%`EGlb0ikXO~hUA zkL<-)(+-_VFd^Z0MTcHbr?Rd)Zszg=_K0tmr4K^(F=qdNxaU`gmd^*8&zLew+my<@ za|!*Ss>M!_u$@LYVqQzKzVM3V?_`U0kEP-dJicDXS(6*VdLMpEn^jwHS@XGhn%jZ) z>9fR}GT`dtCr^5n6hy*iW|A<>G$K6`Ls{vR`YcTUarSBzgH~?&m+K0MT|6FA7WiTO&2t^hJt3slU63#KytN zR^WdA9MnG|92_1ZeV#Nncjk>f{cG5lr|aM_ArCWxynG$G<)bG=DA*=a-X2@Yq6V;p zA2nK#m8&ZekhMi3aqRnd-{wOXl=yfR3|pGa{7g?oj$@^ zS@5E261nWKVOMV?je4uA>w`?Dox6znrLuwa<7Ji`EP2EnWUYhs1Dq!c1`2y`9!_(cdSr@8=E?5G z(6fK(y}>8%>%<%(tP~O&g{<$Z6&+3CE!vW$COq~kZ(4yMwpLh{z3{eKmQT|GJyPf- zj$bfo5wqm?B#-SMI31LB1Q_V>=a|qN(_6I>Ol)GZocrE6`}by6oz;zOE6N^?cWHZX z|GRSZ`Gf=Nj-dzb_-7HR%deX3F*2Mz6Y~1_`d)`og1)u(;@10&*MXYaMvjuRrl zQ_Vvy$=Y@TggctjHb)RAYMB9i-}>)9mUi$SSmFWfbw_wxrR6t1JTtFyk27kzc0|9j zdbrM0Jw0fg&~3gaJ&^nqDUp|BC|s0b|5#kl};jNIBtS1`-01B?cXc^!Rokzb$Pt z+XD*A{sa8tTOXp?FyD{;R^K&iW`LTi8}u&@C7HzEDGnDh7ID#&Gy z?W@K!A#&&i&S$!0OogY6JbpbN{g?VyYL#W0$IBZmI`&g8L0g z1y!67Kf>x|ePNgbv1R9<&X0NnEs9LW(GevlO;m;*_4LfI5ty0EN37~)wxt9mPktY? zmwHNW(6Qxl+j?4&g0Z6df1fVUEe>Sl#RGa~3I1A0FY5bI_r))~f3_eiX}l)i;?L+0 zGZoFA3Qhz@cKpP+y~PCB*#73DJbvGvYJYmcYUp(>=4o^jvVJiwOF%Pd1W(4&yDkM5p)ZqB(yeeEXRhv6dZza7r;v%1}tX>nvj9$v8mo?ZT@g zBch`CGwUm%_$|dpt0_UNFOrX7Zm+~ z#J+w?5sQ{BpLI%AIf7S_GtYxlohVb9k{LaKC3%%>>QKKgUg50QBcodA{ z&Id%#=)bR!JK#6Tt^rXm{(cLV(}=kmbO+nu;eT|E`p?}dY(+TAvVVUCb}@(CmxJxfnU%+ZQWPEj=YGJDLZb&jC={iO`*b#Y zn?N8HA<$H{qX4y4UD{htPLokoi;#L(`G4EH{|!(=UaoW3vSn$jG7{{?IRe)WG@kq< zj8kK_OlZbtruQXGOdbH&HSdl;8`GE)7g|$-HqjhC`}#CFBl*+S{?j7Hi=4R`>sqNIcU3(mQ89mHX(~pTuErB)Jb0EemcdIHis0_iuR%#Ra}b zNgTX07z4-e_ZWS*@gT72iESsXfxp5gYEIcXAJtYBeYi*^Kg_YJJWpa2_?)UCr-zO7RPVw z!K5K|ztecYz3pS)EdV^N^^MKrhQrYC5pikLgx!x91Z#%Bbk0_NkeL*ZWCw4DbILl7 zc+}O~w$2$^eynQ|ok@tuPOji|`aG4sZM1f(TkI!fU5Z@xyqoEHL7Gbg z*xG}(r#}5UfxLP>&!A%==f9{?l~?%s zuYHq$XaVOTfKWu~zf)*q|EI?Fh4qGoB7UHF__BYgP?hqN#h3G)=Z5KrocbI@Yz#%? zEy{jwv=2Yr)DpO+rr^q2N`^!J&Q&RWeYC7fESbd(DCk~7IS+uG-r$8fB> z&|*~UbZW*LgrAR^T|{HwcCug3g!HifN5FmyjRK~|oM2Bj_h`b`%IB~34V=lze<)`#@ZBGEr~eBfs6o;9k%$U^ z(RhCXW&&WM5g$w_@lOOK1~>)}Xwd7Rtn9k{>BJKrpBl6mlK&x+Aj1KU@Lqb1u*T4z z&N>NPl$-m?Z36MWLVMZQcLKiK455((;Ns#rI-9Vukz)g<@OPK7P~;tI3mGRTr9a0OCRdplOx8nrBER?^ASiX( zu=FfNJIo4s_f9n=LRnneU7ED!@#wgER!PZtl+`y64H_DncU+M40x$HS}%`hW_nn-NJIWRbwd8i8C%hg6h@`E{czrL>WNb(VCpbvKc<4B6I zgj((RF`$3<%UntwTj`JG?vLNq!@rVb6+Vm`=#0(VWCNNeY0QV6yENP04CCNY2rjS* z4m40<*(`U;;Ch7qE3+d9y9c_(hCF!oPSgsA3#Z+`O9d!`3W`qZ_rZBgcfa%P*K(o+ zi_7O0_SPaPju?8)j4)m{`B;@aMRbhQ~U39?X$#EC zG)Sp}6Vd^iuB!*W?S>P&dFU;Ab3{@yACpc4lmGr9Ff{$U_t+Kx=YSn^5FekdV263O z;72FXJjR(&1BA{LWu(6HKPfs7!sM<7*W~e!t#l1!8cdF)iXv#U!kJXt^^3WObbbad(- zJ`grbj}^Y0d&!d!{V$s+lD})~4K#M*aFx~<@>tPTHxA{~yuf}Wn{W%Ff`Oes=la>cCPO?z=`iFkUzQTPH zVQDSLy^2HoWX@ps;403%igQs2HP8IeUn=}!+D$ViI9T|2~8|-_3>GGR`6I`V&87X_V5n~nV10>*7eUr z0{q+eu1Q;)K@0R`qkTx-6L~D6n%!e)Yb zA!kT|L6YnKgVHPv+A5(<>3IW)sOR2Mx1XS)RLTfwq0kTnQf)Y&$#N>xQ0TEZ6ibd8 zg_YL-t>JkZck;Kdb4?B3W^E?7cZo&6SLe?sHZ`2N4Seu_-)Ehna=E=qiZB~|AI{h$ zxq;I4BbhO%S{0-9LZfFILC)S@46Ur%&zB~N@0F6{0gVK9Xk0MH?k9%GjTPPbV^5FG zln3QyUZwCc^1+z9gd;0LUtG8!DI>_#hC+iW#A& z%fVRmB+#LEVQme`mID)qo6*$lX zB3oqpV7!gKTYE2eXpP?<+ozimMT_<)%A{g^Jc(HxpocK{1UOs>SOJOx{IGxsug?HW z8Ywq`A|OAu{$|KKUhzfttlghS&7ZgE8f$%Sh-!6pcOIG8LuM7h6Gm)LxKMjNXA1&) zP;B`*E8ywU(rClqt;dD?8Wj#^j*P3!A6Lgo9dzkd@`k3GKG|5?qmPb@jg?eUDVwAZ zd&(Fx{N@1z@~S1ggf1k!NQ{vva2QubSNFc+gJh`~hxW4oIt+s)FOubu`$bnzzQqT! zp@gz_s9gK?$ZZ5aTX2?W7IwbSJQblO8BdrMTQpYhJ%+eve(MMoqB}#mX$)C7#Xd1Hu1P4Pqi(aF4@Y~^UmJcq{6HT; z`R(Bx*ROkX13#k)MYtsx^l`{+ZHv9gXhg0UR-@W;MhUFmz2``NAM=|7S+NmjV(6#c zdD|*h2xzzgu%10X0*Lh5U^`; zLmOm)jr&YILwIuN9i* zL@oDZ&Ndtu2M6^) zY^(bleX)-@w4_lfOLXpg4?uh# zXRf#hdbJGV{t5aIkaHSpBwS+a(sX#mWY5e*Og-Jm#42_h&Hg+ce?2zr8l|=h7)mh; z7Q~Q)UqsccVMnD#r-VD|AJ>)Lclm{!GHW&Gz%m-Gsxy9KSm%$Y#^c3YSyZIcvKSXw0J}7AvOopYj5}>lOV%Byo#a0it$P?eC>$+un^MTfvL?7XOBEGC+o^5q#k14tW z8##k%4kf|YJ}wOt!ADaANs?LfFZ(9F;#k$Rf`Qxu& zZ!8Gy=w9VFZ?H}j?J`$}sMjO~)w1YRSUDY>oe>5wqP)Y4%*?iT(ZD}n5F_pf-AI{n z)Jqi!xCoeu;Sr?9#Vb~u`Y;n-_dJSzL3`d|oySxzV#S)5 zY^oUp^=YhSxTrrCF*jDdbnw_dQ=m^Wzl3A#r-M3CF#@V4J?Qc2jX7xiP(0U5G_NFb=;oIKYCS zu@GnXph#yeR9fl0eYq0_>k-;-PxBPU3OvojgSQETs!)dhDbOWXA0^MmbJJYx!R+Ez z5+-^}ax&IRpE3K~XLhi!jRw%=Q?DAhK5)@ZU$#sk-=JuRL)56!{DiWxXLa+2qSL2a zxr;s8a=Y79gW9gRAL^dAB?T*H#B2#NVJ~!0P3iPhRWWpkgCo$?^Bu>6a!IDN@^$Te zPHl||X3M#G?1yls6?Q?CM_w@(v;cqKs9$&1a-JVIznWWA4#n)?Qm1PtG= zgit;&j2*4BKtr?TvZoZ&rSSgx&nN_#Ak+z^HXDv~%9r7Io#>&Q>5d^%=fEafp@iz2 z!3Hlh>{0F`Yt$4HLNPYK-akiDbZ&mZt0SPX)X1V8SSrR9?n|ZfdhaOWr z6~vmYNQX)(&>m0ZHkT@?lL@_N&%j7$bct_v*V=EH$3`Xw2t60UR+S>JeckgZZ4T=6 zv`B56b{UsD$4_4h|7unczBv9Y?wT?7A)nuZu{6^I}^Yt&Z;E2cu5IEF0R}IaYB`uiH;>)}FnalaDB9lHaW( zK??WOf!2{6t)rLDEgrp^43jQ6-6NRUu#EukUB#DZ6Gxnzdyt~>wsljC#EnMpN)36uRx z(sTLx0@1#Crj{)I)wPrO#%M*|FOgp{XkHdvgbvP8Fd5Kf z_Kd!rmO?rWWuZytMZ$TXZ-AGF>Um?-Ey>5hLDUcOr8oHiO{ZGNnwI&<%*2FK0?&ZP z6n61BDX6?2nw;^~sf^t+cU@NX4dVIoljU5{zC+xvJ6M|l-GbL{VUVkZz$Hv|X=kdU zGbT?+W?Wp652Ds%ZlW2-MH3AWO7_errw@LW9w%xocGHF)+ku9sFVhgT+jqip8r=3` zsW2=GytqOQ*80bE#m8M@3h$h3>6Rw|823r77!3_F8MD=b)Z~8*dL(70MK?}A$8#yT z`PL>W@IKmxvt$mzI3j7#=v+K@B8(yJ)n%FTcRgv3FCNq5wpkg94X2vic$(!5nY*)9 z=v`VxBwdnxJYT823)fCgM=;5ydrf;q$Fju?6UQ~f^oZx@iUB0(HQj&k+d0R)vzDRI zs&;6`V?xll<4Rjr9z>9;X4GTq9s;K(6FvCAK2-(Q_Toiyo^H-VBFX6hhaw)-ZR5rnn30 z9DM^h8@TWcqsaRR+A?^ld1!g=FL@mkY}l|)Xv_6QGKoiLTcBQ;7BjFWq=F98%!66x`4E*9nQhpznonxyq>zDE(qrREqI!QgmKC=nnha1tWxX zFkaFYsR~5DL-eSl->w%L<8LwuO3Cf=ZT1xi5>-)%rZvP8 zv+Byp^j+3Pjy+6|)V%MP2l?r)VL;9uZfn(`8~o7?@KtlSz{iJo3ZJ;cvvG`(a5)aK zE-sJsd+GX&OzV)znu8yM`-WJ-5iM3iMKL}OIr69Pobx0nFvxzzOc3y{Bosm0ZG#c* zpjj47()k;-9D~<}y0~DD ze)9eseN?CNV=48+>r2BrJCUA0ZxFYTWBAbSqbEhowi)ZY4lN#fMDafg_ZLV_SH*$= zB-Z)Wa_s)!tBIT!5}^C-cYks}2VY=cynF@twHe3ZyLyob+D(>~iF%UCu6HQYq_SS11`gaFM~6P!=2pJ+@SM7qAjcD?a2MuTJxCvqIQ#XT z?F)l}#J@*cB9= zt@XLx5TCL=JMXidQp)O%)+Ad;j@tIeQQJngUMCmv(vyBZWlF~_tOp{NS596cmp2{P zTR*O?8yycYe%)URV3wIS|DGWZgi%iQ3I5tgZMx(<`nGy6?+Uo_(9+ZyLt8)FZZf7M zd4j>z$(E_p;a+&++NO+$&l~x@=RAb>&vOS_a=qufy@>69+f(nKdrB$BC5l`^oWP`e zFiWWj8U14ZrCBrlU7xxPbEFaTi&|#NjR1-I^!@4^AM0oK>sYtVjjIS@vmNU64t*gC91NRGyj!oy+XM=t0~L~wM7p$?B;Mf3nlTj*#D5 zU(L_KNMX_CuwSO(w@1-RyHha!GXI|@{qu)?^`AR5Pyt8E?D-a9(wU#KJ5mD(Ii0nR zO#kuwfEKcFg$)75F_qiBjn;-n;Opx^746?1j7@TzfvU^TuqLAZ`zljc7E<+=V`T|XrVn1)BWg~<2@VN$y_7Gd%jk=Q6gM2!GK>V@fe zJrf~b=?AA^JvIDssx+lPXtd{Lj1#)c!sa1qfx!p%U+rw}4?6?&1``>~3b^Fm)d%0o zH$TB`5%DX1foH+C0OEwsaFBCQKp>* z0P!`M5x~bSlZK6f^9paQ0HyZq_4efq&RMe7m-kdaw$S|Lpz0toqXM}7j74qQSY zZeSqlxFK@rTIo%0A+7!)4b42#Omee>SLLPPfV<)B8yiA2avb*8gL#@*a}_BE!}-Ve z%C39e!aEz=e~A=OH=KPUpr(+GATx>g6?7O?AoUYcg_4JC@SPb6CIM!&N3@@$SpioF zY716KPleZKh1S=5x5c|(Uk_$FVM3kO7GU;95)XBor*L(@oV;!}*_BY!rNpy~f~_jA zPRD#${!L)=hbM`EBb{7(oWOnZc%6&_ZUL$6@;aYmd23tnZD(842<2<$i%v{A5+1qgT2f}Q6^4!4UU&#xxf_}%)`ZR zl>_UTQv>btCUnuZ2$cdotVOf}&49rx&VWL?F)oTo;T3_P9krutmk@?rs|)Ai@*_~> z01>FiH7$d>NJG&jK&LbW5CfioI_-a-yg>n!T6L%*(IxWL8*0IR_y8LQ?GLeQSp@lgBvkiq*0kT86PU+h3m9bZyMDN8?hR|IuRpV@ViuSry!EJ6H=BJrl z7{Jd4&r{V4n_POz{n)W?sBc+@8e@ssgv&X(j|@0iEJwL!uXX))S}8#BK&_3E4xE}S z(F_Ke@&)#b0d3S-bG9HxAM}EJUJ#$>Hh0~Vta+c(ZGtKFo{lPM__xX^y!-YbI zWk%8i9F|gKOK?0wus{3mt&ZmXc|yX>^Np)PG9Q~r)CepZIz9rv_XO?d58q+!*e8&` z)6oI#5v;Zng>y47eAf0?4n63|I%1!eLMsAl{Pz*?52&cFe5fiOrH=ZQnG-W=8HTN`>UOVG?M4n_l)s6wup&7 zrXn)=DL$cI)q6Ig8PlsI;_&mGpyV*Ya%^?b^8KzLgv%Ij2&HOzO9?H>p4e*{|9ZkW zKs8hgTp)sU5e1K3(XQJUAeP(dg{+hMwYat>pG^Wtsk;qGf!GSm9@E>u`FVVHa=V=< zNnDE;VaN>AGYAuEMR1=<-8J#uv8TK{_NOM_-XWI3>B+NZC@Y_LiY&u0Wh9!!r{gvyT{3)@uHg=oqGw`aGVUmEXpj%%JNi^ZS-j28J>qdn)Rj%+W^4_=uE-WcX9ATenB-HxQ124gc@4yMI-dk zYCJh@AHLyz1KQEjID|jGn0ozH z;S=kZm*xyB)@(v6gMUPckOIt!fDg{+m!E=M%Xj!sDF?YQjNq2ny0IxMT=6^J{fd4Z z(7x#Es2-3ZxZ)m zvx9}^{2mO|rW;9>^u)T=78nNx%Uy3Z0~PhETXWNVEOE3b;1?=?m?u{Sys$_tc+FKb zp!TCP<8!y#5BB@0_yna^I@P=ELV8pz8u>akK{9Q0tr>iDiunw$5X_ZO{9}i2=-bq5 zi={KXUbH%P$rfs$;+a2l$J4Ds3^Tcq0`KyCSJim%#3;~g-ruE+E^lQTXMRrLkC=C0 zHQb1Pzs{QJe4#g-yEF1UIwK4 zRY_~tZaxVi5ERE|Nqb3IG&*EC+a!M%)(!5$dIP3e@Foz}LDSb~k->qYwN^r}m!hA! zZ^R{1GZz z7vFI#+%vT2I+xG{_Pm^51fg7keGM1kp4RMxdK4O98cs;9`njs*7 z;Qx?w`fC;dNDkt2)1oZpphDH>{@N_9D4=-SHGyM$<`KcoqaPB+UvwidCL1#PY65R^!<5g{+z73#caz}>4W-9jt-NG%#Tp4x8Ju+GdZuZ+~ zxxc0Yov&X~1i(ssuFcdlU#Z)JT1!KQ9Id6=Z`D>Pc&T0GjFgd|e+6u7SPse{0-D7{ z%y<~w#Mq~k-A7tLxThJiEXSjpqUaihV4 z6JI8>7MEu%cH|W9A~6)}YK4BxiG5SjCev3UC9h38`lJM=K9*S}$C1uoKnmrQXkbi6PvKi6hXi|~-^VcWpOcx)K8STC-~FsWYm zZ@_*X%Rvo9pf|iGs(mmsrea-~IU?v0$_k-FiJHCx!58llCS@r2t8HxuSKYf=`Ubk_RvA zRMODO54}d#1;t5^@dD-h_gEE;9*3!kfLzJhF!*qDZ-be4L2_k2Ssk6sV~JA^?7IEY z2*vkx<58zP<;2Qp1+9HP7wjT+neRHSS5QkXbH@+MoS#!SFd6fb<=2(48jbf7>uDjU zTQwP|`odi-?1;Q1gI`*5G+y_Fv2!5z8&jTBo!x8kK}ekD&(kP!YQblNjS&(qMSBeD zMYY8|Qqk3hyY#zGn;cI>k^PO7WFgm~05U^$h@dlQJ}yRaH8BVUR|D zVjh!Kkkp$iO~&nBvRDe{m<39||G&uq2WXFOVH{kvUHxLmODe6uHh?Fooxp6{-!>n? z;mg--j_lG_%+>>5C&&_xT3QHKafAJ@A%g{K1+wlF0f=!1M>C4A@+drx^$EPT9xFrx z^j=!Gm^6U*i}|9s8L@EaE|ICqEaqSxgi^m!!Ni|=S$Dbup@>)Tq=kTN=ssKX-V}BQdqC}>3RI?dqA%@hFn8ytO(VwN7hdyl0UKOYjRcmxqAW__s$F&dBe3zfSmr4% zRd?PYf@Tu{5!iM*_%QVYDgpGyXL0wS1~vQ(UH1NV(IXW@JMD!h6(tq+;g{#*NXHwGTrI@8LfV0QEr6=@ruZ&1p&OQ zEyVf~#6!j{EvLAvLB2q1BrUykfL$)JdbiC5i5d^_e)*HSj@sopwVZWLXV?z-OG0PM zFGRW&r;W@>BLAYzf9W7lbKHGlQ1yU8*;U;T)x-kR)CuRzqa(ej9ho~6Ie&*D%S~o< z+qI!Go3R}52t9l`bDh*6iL@sJkY4=*Ah4*xe>IBv7Q7Ku?V8K zWVC3Q2VbC;>H3vd_zoK_{` z$iat8&u3Y=7jj@m_sEZ_NxIr@5yHuq8=_M;_O$&$rk4gCVH_cpe2=LfHEx&-R36B_ z>CCZJn9msW`5ZxG*D=3EW!CP-m%S|a8_fYIEFH`+%l^8W0~det?++I1 z8E=u!B11|QUxnHC)t(Sf8hCXqpWdlFK0N@+>5Q<|Bl!$2@*h?kxj`@1t;RxPM8a&( z{IZw0(6ClAo#FSK(sB1VQL-{RB`mJ2iYxUKytdza6!T1F4V(vKD!K;fBZpB^buroP zz=nt|1Q=X9Iu>6#zGLNm>$1_vUB{4``ijxwy1;h8Tn3>mqf%Ru2L4%bb`gohman*B z*eNE|QcsLW#3Q ze&otX zBA-8DzKYg|^IxCfJG zdTlmN1Q-tjE}+Krb-d>P0HEr@-U3pvppyXWJ4$ zWzHP|d1&^=!GLsiU>pNpfrNcev*+xPk2!J~Es0pMnz_77#lwe~lALFhB%E5SSuSE! z12K-Z9{tx);0=BuFhMY*Yswh0r#eOHpyvMYz)-23@4s1%np8%t(n3V^zs}p$5X_I5VCk8VUR2F zKOx5-yPulMhkteD-8v;{MEg*5tP;QSgdZPL<*T8{Rodxa4BlqWRc=FIaIhj=qyak2 zOmzewRKzOsdSD;*6!4ssGvo5nxgpf%#W_Es8W_%iHEZK0s;1orWm=UY z!oap@%F7~;M2}o$MZ(wn%ns*~i30AGR1^Ll%5m!=!zF?VWxp^BV9Pbev`Y0>GdbnS5Z{kGcvj_8=26!1J-~l{t@M# z>z2Lz$e(?4!kxPSkx9hqebk@}az#*@Hi~L~u_wbk3bKfJYOJQi$s(i&hf+H@2Cu*W z^z|5k{?|xAasBU-{Yl$s!Z%EX>*&&o3ON)@@O#y8(yPL(R4-x@UhrMSX3JEvAXHFL zkdT4-gCB3A*1nI_$MjZvW>JL^cUW`MScssa6|ek39pt(k%r2!mhoX1z#=VsRX6QZ7 zQywyrXd(+aqCeVsI`A9i1dM0?5gm({*f2)jpb5LM_LE0d{CpHt`6q9M1HvA^ zyH#^TQ9t9WP1oVDV|*(%xjYuTR*bH0g{S*Hno7a-v&MN#Sv{&!M#!!WWqm@G&Y!Y_ z+->qh@uNsYzeCwG+h7qf@8=!eQz(a&^1h~wA09=5w_g%KiVv2o|Lr1Sq{w$AOz7n5 zT7ZfZfgb`~W>{*S=l&hI$v~t+uTGVX_D}8bqBiWYWG-3>$7$OmJQ(xSP-@#=-L9E~ z;Dg5cksL3Y&qiFRV5#<2Bm{5bm!~%VO=87wgMTlXlK&~>lMnn~>g_3Vx~Qlq$416w zy5)#NUJwIkG47fZU4TgdeNj%6Ogz(vVtfLi%q8hsq{-HD%_UriA2K{zMwj>BTv~|v_ufNMEC4CH5VT|$dk_riUT~2b$IFKb zFgchZ$a(3Nn^f+kw!Yz4S7zl3Xv)#BHv@YqM;x=;Hmgz2GV8AgS|Obi7s&W=o<*X& z0Dn?b1yDq1Uk@#LsA@w`8bwzK>f)e3&3;e!LSOLLPp3ZpnWNIN1_n6z48XE#z7y#Q z_?Zc5w=lQ;k@~wMti-gidXwuh(S?g?F;S$~inz#Yw)!74@h-oP_@<`1`l%oxL?KOg zNI{H|rR_J-k)q(+yGKCaMeAHA>Z;*U197PXn>|9fkq3H`y*c=UygBOc)3_bPzFyPK zEH}4|9(4a!VCc^GGriyk1ZG4%%<6l^2zeI{jr^>5o-RxTtW~sa_14~uFxSW_TfAhE zx~7-41=q1jxCo9rhr$(pCsT!|_C5U#i>CclgQ#Upl)TNk5x4c{4qoVi?!uG4w_?sz zIFG+OgXf?6Wg!dgDX@_hLqh-GfTF774@s0H8 z{f&F#+@*dlPcJ8;V4W=wVVg!Ll#yaa(_qaaYfz10Dq2lM7k=@W=;s2=5nwJV{G`8u z(?ZE&gUs|y@s0Y%#s00aHCfR&0wk&BYERSKskUJ0Nz20OkeeF1X8H&}yHfM{`C31b z7QYC7wmIWpa!IhPpGRv}9?XKk$h7gsqvDMxO;JNA1`qiq#Qcc8(i;lpqec+P`< zJ3Dq$;qgLG*}8P91)z&0d%&Z)?v7@}P(R%D0`6&?&=8$EcivX?u5A*gs7wP<+#=Q> z>arc4dmq+qZ0uHO|DG9M{FxcXcnFGXYxVJ(ZKMMdgFxQ?`gT+!D$M`rN}2r;A5=i2 z3Hkiu$2hYH{fl4r{tjJFBdcp^OcT5_;e86MpRdQRyy@9L>OXhRLSKh;gKeZ#R)l|* zFCpMnU;(`5OG@TIhB|j{IKS}ks<5#-#t)rp&!DzL_17LOv0=aG5Zy8TXO_QZmIFz3 zw=^KlH+PNnk1w{ihXDT(Cl=rTo4EphVx0RT;VvmH`$q*gt2praDN-V|vXYg7?B5a~ zKY(SPgo^@YD}9&m{;u?J*+CCS(4IJ48~*jl_V3cto&enevbWdkJ7BV!`Gz~S#lY(x zkaMcKssm;Z{d-wItu1v3U}g0lVij;3v*3?4caFNG$-f+KOZVnKT$VE6vIf?dA5+6F zE`Gd9D`i(tySIOm|2j1EX~V_^VxR=vdkH#te=)mWvaa@BNm2>$KOZ*vEjPks$bwvL z&P4HG;Vj%xo)rCAYt551SbipMi7oB__H98JtM;%5+o5`&<*Lf^$b%sw45;;xp=!3) zTAytoys|&ha@ZvcMI=jr#shidac;qxY_N@kI+=8*b6}2fa}G~$7!|#b7}-GIE2|Oa zRoNTG4BHuT3&QN~Wd*+N>9qS_POa-!&3Kl$|MmKm`mrF_-q#R|HD+V?nsTglO89Ji zx=htp5VeYq0SYO`4O|Q56$Mj4kHNGy;rm^nlK@lE9WFF9%y?kVbh6$h8O^Fy=8r6+ zxD;;f%4%}D6VO%MgX4XEz$M_i?Jh;w{ev4+Lybj30*;{-4^+2I?vzTfJjN2W7L&B?C zw`_~vu_inJ&k1O)NVhA5YpB+f*PX6)A5%)0cpeIp7&l4`;GvNL%Si@curiO+_T;`Dn8vObk z-(u?}H5b>jeXq;evxTo4+yu{$HaeuC2$LP7q>&R}=zuqVX*^hH0#PjPrKUHd{7y(9 zDO1JHV~LIFn4(Lh_ddP?d-!EocxROm^`PCtmqE=JG4Y6Am}Zjrf;7nX(}aRD@;ZE^ zuJ#Iu%3~0n|5e6KP6=f)pOWE29!O;_OwHAh&Z2++&>v{;${zf+Q9b5`GfW4^1ZOwU zRZ%G9h!*Bsv!>R?ENF={poXbiZG(cgI&iNdP*KDgIY-g2LoK;y=cgaxApz6Y&$(`~ zVqsxHG;=G4xwLD~S#x#f^D~EsOk@|cqT-TcpU`Ix>asSzS^So>aBL}1{2<};XKAS? zPZ+f1b|E zsWanu_-!qqCb#V1yDLxzLfo{410oo-6>l(nm0_#RwhatR`Kl?q&Q-A%2$AXVzw941vm47_*w>3y=Bpl;@e7=C)mC&yVBuhe+MzHloW0*O z7O8)j?xT#s0!vMs%jV?Ui;bretQSE=t=k{)Qw-{Pig{+_>^u09Q31AtJcw56Cvt&& zet8*IA7eI|-zZ#pejh2RBDv9C%=>7^P03O#ielDyJ7K8fWfx9gv`m^6ojgGu8UZUG zwtp$95MsUC-m1E)dg(jomJi4K(iX!X-;BU>XpD|AtEFaL9tI%TOL_!trEbWbZ<0(P zR5-m{*k9z);hme36DRK^h#93uE%30p_987ZsOf*Mnd&Za-6(K~6F4LA)~nE=^0}Cn z0lIxl1725VEj8HB@Pm9Tg7(^>vxZ#>HblnS$5GdecVTT#_&iW57cE#E&wx=ZU}@8r z8*Mx%<*~TF-Yc|MMYCHA=ijD+vmF`A?(cPosd{c~#SR)@(ZvL*l4RlcuFOk#r&VJ9~QVRgvWb7P25j zKL0|`Irw`*`ZUry6#>~Y^%!LHw$wqFX+ZP-)iJfmR~DT{l~azV{jnVwT#0xVg>aJnbCHBSiN_Og51H)7QrRK(gHNBqhyN z`=zzk=s_j$()(^q2|2kucjNN)zM8?q=`vqvmAA-B(kIbZrkrUpPNPfml;-~l%`Zte`spRd&U52 zJJp(ovlt=fmk>p2~}B)dj$I`P z<4H<6x91(MU9c$U@w>G4Dpu0?UNhBckbf5_7H3`!LYuE(s2Cq(I2`c)g5NH~qnqx$ zQ(96L&}4m;GFV~ebiNo&>4?35&qbrfaAIsgUdnH7OG8!RYg+sT4v!*`9c9FH6S4XL zF0#jSrsRT^)oQAeY){5oZ3e)4Tr973Kg6PXw5Cw&vK(u`U-H`r(qJBs^!-(b$^s*4 z_H1iwTlhj~j%=+VC?&ahy3=q_>`Hg6yls7KBD=QMbn%dESRpx?XTx`Wq#?KaOdF)s zFwd6WM63&v1pobSHs~(Y!Jy8(R z6$16_$zEY%BJv~C&NK<$vbsAT-W$wzDta=b=J8{Hb1Te|q|mqF@?;CmExZAJs>+r* zrztM;MAq}MVA0Jcsryp-E$-T}H>}!vg5aT&JC@Jq3zA;Fith#j0cc-lypJL{z%qgR z`wr9(hn=U)(!5cv$4623M^CLw>PQeV*4cY<7_;%BK3_;4_ckAtD()}J_OjFmzYQ|< zK9CWJaK)>X>E+zuewTA#bq{5l)-IZ%7`+mFz7mg)JK~*>@tNwu1F0fJJIkcC+G+b& z%|4gni;0r%H(%<+PihIKrNZJ>Me@iQk<=DXexQ9W=(b86J(bN-2+%CnMHM|TXb9yQ zT|;_?k;Ks_PJNSd7FW>ScS@e`=W{twgyS86!r||UE4MyEx)=7~%k{E|{`cS+Ol{Pm zo$2<4)>l+VUD%V=wnFzCj-Q7BBf$_Fzz3H#B&S(eN7H*-E-~|uc3ndrqwyqxuQ1}I zm>cxap4CP>GRz{m`#o%p4rsJ{@|Jo&IsW;zZjBY4Va~7*pNNPQvR2#-#oO$~JZo9W z2G^ZH_LoW2Wj>u4M1rOvWiwUk1hYn^jfbe~qviL`kr4el1)Em+VH++Bma z2X_hX5*$Kshv3$@(>TH1Ex5b;ckaA1b7$uJ!_)lf(`VP-yH-`Ls#OKncC)3rA|tQ& zGZw6VA1{|4z#i)Ra`G*~bI7;w_S-%>G@zW*m+Wdj2`k(}m%y#uEco&qS;?8(e!N^~ zi2^i+vb7=K294^xhMEk-bcy4kgsjo6Xyh=wdyL6HD_sXwVgu|SdJcOM*wiM&J$0hU zC9-89Fj9%nb^AdC*?^^w4?ULir8v>|Y|g_-aeL;Ht40~o`bOFoOnj9snc$(EzDM=S z=P4t{=1NbVM~?$sQkIpUsv7f%6p)YspiiIiQHi9gwHbZXF)tcFFs zCed~1GR%NoAO@5gdVP35-C;jp>}B7l@>WV?($=(d(3-d~eUiq#Q&NsBxE!SnHehw7q zRRu)0=u&(C9zqnjTQvoJVv&(m88a8SA!XlC+hu6HM!!ZxEDk$2k_{aW(}QVTcWUP= zch+%lfG-5-mwdlU;?KZ$q#vEO)eh-b0g^|OH{4o?ikTT%*TwqV-FrDti#*Uo{NB!O zSrwSIdV&0?to5u#MSpHJ>$CGa5)YRT*m!tH`hK^mMNvq``x2cA9Gr2!aasK#Cc7Qi zrRd+ybP2MN*4Z0^THTH-i#d?zsRx>rp*tJ44SI0No@F)xQX19-(sEKua+2|d#?mNyYVw^YfFxL24iUdJedzUKYiG=dbx|GG^3YT4GfHpNx_dk-%5pJ&4mEVtusG zYW#gna!W`}yoQtK5>ZYDW|BOko1UHCe!_Rc9El#*(|Kxs>IB3V3y<_Rs2pXaFkY=FHb-e$45H1_fh*?xZQyiVxCUC=<6+L6P%JT znvamYPm8oU)Y@YUm=Vfi-kT+h5|Fd{kV!-L>+|b9Y1vjqgE#V0{zZj?M%a*pLvBFR z96ByR1T%R{I$!4@0?3ry`RSxl1Y02!t&d~ot?scN9Sy|CQz&Fx0Q6D}ws>?s&-X$z z77TaI7D#u-9!-gB3Pg(C?+M97R31Ti{%N(?51}AP6jz5hntvn5t!=?&`Ykn+BczUS zrOzIP?CY5oYMQ3L`5YRo zzp`_MeglAcF&?Bg&a*Ez;YFwsXZE;5{dv>~Wk2^JhXs%H-8iuY`C;r_c+f>aMlb}w zV=;Y17?xG9D19D2dp(FUq)d)6yPR}TvXv)VM}Iyd&!wsrZCSz?IvmlI*z@@wL09Sn zs`j665FxeZ&%q#r#{i{2+!Bn zI`zJ2Mr3-Lef~fhqMkEz zt1ICQdSMp$1FsyM777Z5QV7DBz&rSiQ~i*nw$;|Ypel48+2DG5twm+-fF1jL=lq3a zKO!?hi$6jZ>m9@{2P@K1)TyMlmeo`>BELWw!wF_XuSK`smxJbUA>DDvp}roP-n4js zzHR^bww91Q_M|>n+kp#Gy?6}|x3J_Fxt@2DPapT{0d@ZQW0F^-@WkWwV5+Nam>z4=>Th`lLTkG5$Wcy$sk9hXGu6mcTvj##| zbmt*kzs9lGUB51d*yPW}z$-mTH+gVE)Px#p;NJG&Ccc`ST1Tpf@ABxd!o8+ zl!Naj5kcE|{=Ks!BaB;|OSzV|wOoH1jdQE}|*XI!xzcfz@IMv?e1tvJuSJ4Wauw>=N>C6px8n)5Rh z4lBd7-&zCA!K(AMC(`fF`{O`xyHz(L+k27Q6L!(pGu>~!l=%s746nPMU%>E4$4@Kl z@j81Xs1YcWaVrSPF%bJUHzkXUbFyno{NT3IBwisKvAf?=Bv&8$p$eH)o+F^&utFyi z)%N(oCH@ClZ?2+JQvn_?TQOAmhrGcfPaS%;iJ+I5%vQteVr%ibdTW#gn+X{06-J_KF#%&oxQ-^O_~7#C zHQzgavUs_7m;%z@sqy$cg|+pTC_wKYmb&zlO4u;=KB9T1Hv9IFo})9bN!X#QZbYr@ zuQ>F$Qj{jOqfbsSDeD=hGq#d9I%P}^2cZe*esyQf!IpyJf7u17zuAHhpFz}mq64`H z`x?1Os4Z2$g(w8uVZMcm|Kj1Q%NEws*V9R}Q&hjd_D~*(=OS)LelPIM=J#otsI?3P#iN1#$m}Az=$u4p52x%&W-T1I360;wWs_@+W3B ze*Xw83gY{iyq!PJA`ByM6|Zye#SuZ*{x^qZkt5!{JSzT) zA-7h`q?Lyr3Cf!Cf{7Htvy=~E;@FrL(#6zWNg}?E%+EicVX4gCZ0i)tVsKlXu~j)0@UKI0=8;oqVE?EgS?tPeoG1WI@nV8n9nl8EsI-mUyQ*DFW$~QHaD` zbMX(;7LC`?euJAK#zr47C9_j*f8NJ4ZI#^6euBj!&7$xw89J&{gZ)x*!=&eTGMgMy z&vvMlduHF^UyNx4&*PFbkv#T&T8P&3 zvt#d+uVxx_NS3YW~4YOP2chUC7mg99HkqR_-0lPj!^LHRnc9XyZ18M3S_n>e14& zT|2(9iAl)#R~_BqVnAOFNcu4SB=F0SpzM4M?G-xfJ+cnId!W8k<#W-D zt%a|9jtOo1f2!Z)a0D>&d+i!X|<>N0s+W41gxB6sf&@O(juB&J6XWVcC_pu`M1S}JQCf9*OU$O_i z>0hQg=vwWw5M608_K3hM6m@4c|4=v+p@CT?Jjd zvV21fBFJ`9a6jrmMZU1Z(x+`Iw(Iko4*>-ZsUj6r2aurTPVv;#@K=MKYk|>JbE(}n znN^2W9*rzlrj_@Y*$!BQN!!iAe~hIT^xSq<6R5Mw`wqufaZ|4S3A2ipj|0JHe^z1Z z7oSBu!-fg+o#4Z@b2UZzh)#V@fpZ-^%;0!vHaJwXZmRZLQuessRS8z}gmXx^BEJ?^ z(|l%qLPiBi)9Xobx9cxrMTTf6-Qgep0d+|ACkI8&>Lj#>chuRnrXHo4Y}O?>mjMQd z_@y^iQ(64ze@My7iFRCvB$>?LUZFR|Q_{fH}#|oU5%zg`W zOTQDJ-`ntn#Pw-(lU%PbEs`PsWQJwBjZ1*a_;O>5=qUOws7t?;>&wz@eVm52E%yc% zYNkUPLI+x(68w_`b@yhPY$$xzMe^S)1=#l-#excgpUO>vL6n8^*=D+QGHW~gVWUVa zBk0By{JrJ6H#p@wjl%lx=*JKPF8G?sKH^p$2g8Q+Y-zMZZL{3o7-WYggh(cq?Y07Y zZZ!Q<&?0*ly1Fo%#^c2`scuF&(Ym$@*;h}fTo_GEG+KT>WyUl_lG}M zP4+$g8F^=qO5vrFtY%0!Cwwvvg;~~TTxuA@U^Uwe66y|_Pr_&t;3@=%nqd&o1iDCsV8$#x_5RpXj^CMN59OD+z#5gCbC z{=#8n`f!WO97TmkM9HuuZr=eb-q%+HpKL=d*j{aBAHpoIfr+LK*GuymjsHEE zC(zx&^CHB&H;71!Vl4G4Erp_LZGC@3Ci<#7^2#A(Oxv-x8Xly&mzob~z#EV~-#tm@ z{OW!T3Iy2jKsy6rD}=T5h}r=3NrH7CbtE1F9)ycrQu6lO*|)m5T-fG)a*vBV*lw26 zEC^Xki|QYrS)MiI=nG6DBEMiI>JpO}6J$A7G%b3St zZ-|HqrXg_&*rx15=hBiN8`EF2ARL$juE;xoEPQnAhVJf*Dtw$gIZkMOI5|8<*H)gaz#Pp@dp z=TWXuHorxyWhss)W3S5x2d*NjPW$Om)@Is1QvtXzl3TX;gQyNB>&Md=$410q@%k!L z-F92#N+QMSU9_$4#3d~z&x;d&+J}Ri=ys1uq-~&rqLo2oXYV`qU2yYq*r?NA%xG2N zVe%{wJOOXh6DpV)-~PL2vN~7269ZCRex2_F;%U>C+qF2+hb4=_%&_CL76F!UE0ofxjRSx+QaiiF1!vi zY0Ho(yx_vsT!X6jTUxVs3_@ger~JryAy1IHDKrn?e$#`_g3Lym;?F>TvyMUuXGT&L zMUK>&`nm$3;Wk_|XsSY=&cH}O9g0=~=a0_)!E`p3V2UY`J(l5(F1o6!YPX36ziyy? zEB!>zGy{u3WXFY7(Wfc2gHQ)yA%@=qx4j&T#QhZ?zG!3Z5@DRraMW4MizXDN+?VB% z_BdfM1N1#Lm$};U@0M=;G7P+?YR@O%)+2E$5~qzdGP@Ob1V3(&*NV5*S=J3y0`sDk z{T4~;S;}u}qsIU8F9b3E$}_!BKB8KkUrq{?LJj(XGOo4Z_*%OVMYKK(X_;5YgC}K{V%NH`_7PcmdnByX zm~w1uJayh+^~ucMv($QPKXJjtWivp8b}|pU>Px0Z`7_iMJDbZEkLQ=mX+-1O-J(bJ z`moscodtsI;G=32iB!4iBG@Z|C!3JfO?^GHQj>gUqvlua9!t{> z)6t*c!PD0sjiv#NPpy^XNM_7}jX+7q6yI}8NPjx!)0VNfW~H05P;Ka8M%=^Us)%NI~>qDoU5KGjGQl&4pL#Ni!XV-phHitJZi@JE#xtIS0EaH%Z;%1uj@PELXIP z>@!5hm{cI;fOGDqE`(S=YN$d5w6zmAq}S^btl8swEOW?NRQG={oi>>BTF7(QOTwnk zCD-wUm=XG8!8o3``(N8uy)O?wcw@aKU!=IT$@^0~x{e(eO*|IwGU=g2=S=3AA$dDN*MY`_4Vp`8=)dY< zqONIO(r9mnM#3%N?X@BEx}9=FnxBY?0=*dTR19Wz#)t85l5JIPN2@i?l+K z`z}Ygv4N8o$^zlG#*>8!wBiD#P2%$%U3ivHwNwPXXf^m6&_mq-si2yYySdIuU|qmsE8fNEjj;mx_W|>z}dB zft*jSMpYICPdGC`9WkTue|UQ8p-kcW`1?E~B`FDY-TR5S!Gt=Vr31J&y2wVw=Te|X$ztV6uKb5v6r;GYffoql<~Vu`C8 zc$CGFJSy|mw|IOu0LmDQ?zC4-blfOFhtZHItBFDrY>5C|{3wOdiftpJ>?*(Jc($KD z18(exUZ7FiVGCtmbiUHj;oPtkw8@`p-6T0-emuk=0TC_TBH8wG`UTLtQA&vL@e*M9 zAnA2V>LfQf9kW?KQu!^d4JU~- z>f~_I?g*;5|y8Mn?uMo$6)THGI|3Bte-Hvg3OhNCbmq?x1N<{RQ_FHWK1xaP7vOqGit-CDWSzToHMB7iH|J5nv&}MM!Q=3gi0!~VZMJUXmMvRUc!?F3 zN}R;ReC)iYCB^em&;{a94h3nsgyg;?k~&LB7Q}04KzL_w$*k{j!LJZX%TO6qcdy#& zW=o!{NJ{qU-O?XjNVj;0MxkkUS^+-sJ7EzWU!NnEE9YNtrrLi|kpJjHl|on#mdYm4 zZ5<-`1ieG$xbNzJDxxOWh=BgNPU>eDEO-GfAltGM59Mkq-d^20<52LJ)2FT8?SeZk zyIK5xlY7>b^M}kt*^}Y-FntRfCW7BmNHtK7SUKvC!H5hPbm``VnhU@U#e^JwJKr)B z^6fFp;gPw6_4F8WKfE1ckQ93B72Bf6Y~S}v2$toHI~#3W_Zc@;F1WAMo5bl_SmG%` zu)1XmkDZ&c8VJZgRzosPC?#)g>8I)=^?fjF67b(>O^mUvzvk2?`$B>2xz+8^cL8=H zvesHmFezGyaTp%`6wV4rF@&2|B3lWbt%FHBUUysH;cU)~N7lP#_u_q!U4K&&%N-AK zku+wK=jn)xW0Bg29oUveOZO?PJ2;^3M;w*K!5_#PM=EgKekC9Hxz;YaHek`#UhPmF zp0f0b98w~tO-5bqTdU)i0cayu`wn9!>!^y*q;0)4oM7`RZ&&e&vC}HNX|GxqMiV|F zAQ*C$yp!fDUEb>pZ$>2u{WBRN&n*!IQ#Z$aq!T%{2OPGxOi}o0W!T>Ysk!Sh*Q?R_ zu7YILzS+1JdFHqq0Ij?R;xMSEXC%Y@vwn_VI7q~C z18Yba81=X-{$XQRvWJKl_{Irii7ybI%8m>|}ClmuvqNnm{n8wVb%7IRZ!(DB_QVpt8Pe zlrZh9yM93n7FWv-Ui)}iT4p$Zy82ZBYLoxIQZ_mOH{8RF%vA!TU~^nIUf8-?UX`4z-^1x**llMG5b$*LyRwZSEOY;5eg zr8P2|k%gO#aF@iDDBE!C)qa9OuBlG(jP?hu64v;|h?+nF7nor4tSD{fp;6__L4ALR zLP%C^U{EdfD=QLeDE@IT0wY

    5^Y|FMQCq&bZ)=_Yrj(Dd^(qsz#QD70c-N-N_z< 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 Xr-Fvw74!rH_)@u~sff9F-S58ufbu*v literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/images/component_tree.png b/docs/nightly/guide/en/images/component_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..d9692407350138e0b7597e8705e33f58a463357a GIT binary patch literal 3724 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 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/images/diffing.png b/docs/nightly/guide/en/images/diffing.png new file mode 100644 index 0000000000000000000000000000000000000000..4c243bc759085f24ada3be039cb763e1d59fc2f5 GIT binary patch literal 23486 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 Bge?F7 literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/images/dioxuslogo_full.png b/docs/nightly/guide/en/images/dioxuslogo_full.png new file mode 100644 index 0000000000000000000000000000000000000000..7d08f2af8f057780eddae4b0f8b8fa753b69e7f8 GIT binary patch literal 59292 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

    ##0PXrvufB0wJ`%=YsvNItF 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

    sW@yfIK5!0r3C!jXOp{;!Mh)wCw-TYJeHj?h7 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%0AT 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 KTJSHwum215)xFXH literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/index.html b/docs/nightly/guide/en/index.html new file mode 100644 index 000000000..d7da5a4fd --- /dev/null +++ b/docs/nightly/guide/en/index.html @@ -0,0 +1,257 @@ + + + + + + Introduction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + +
    + +
    + + + + + + + + +
    +
    +

    Introduction

    +

    dioxuslogo

    +

    Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust. This guide will help you get started with writing Dioxus apps for the Web, Desktop, Mobile, and more.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    ))
    +}
    +}
    +
    +

    Dioxus is heavily inspired by React. If you know React, getting started with Dioxus will be a breeze.

    +
    +

    This guide assumes you already know some Rust! If not, we recommend reading the book to learn Rust first.

    +
    +

    Features

    +
      +
    • Desktop apps running natively (no Electron!) in less than 10 lines of code.
    • +
    • Incredibly ergonomic and powerful state management.
    • +
    • Comprehensive inline documentation – hover and guides for all HTML elements, listeners, and events.
    • +
    • Extremely memory efficient – 0 global allocations for steady-state components.
    • +
    • Multi-channel asynchronous scheduler for first-class async support.
    • +
    • And more! Read the full release post.
    • +
    +

    Multiplatform

    +

    Dioxus is a portable toolkit, meaning the Core implementation can run anywhere with no platform-dependent linking. Unlike many other Rust frontend toolkits, Dioxus is not intrinsically linked to WebSys. In fact, every element and event listener can be swapped out at compile time. By default, Dioxus ships with the html feature enabled, but this can be disabled depending on your target renderer.

    +

    Right now, we have several 1st-party renderers:

    +
      +
    • WebSys (for WASM): Great support
    • +
    • Tao/Tokio (for Desktop apps): Good support
    • +
    • Tao/Tokio (for Mobile apps): Poor support
    • +
    • SSR (for generating static markup)
    • +
    • TUI/Rink (for terminal-based apps): Experimental
    • +
    +

    Stability

    +

    Dioxus has not reached a stable release yet.

    +

    Web: Since the web is a fairly mature platform, we expect there to be very little API churn for web-based features.

    +

    Desktop: APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.

    +

    SSR: We don't expect the SSR API to change drastically in the future.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/custom_hooks.html b/docs/nightly/guide/en/interactivity/custom_hooks.html new file mode 100644 index 000000000..56817def0 --- /dev/null +++ b/docs/nightly/guide/en/interactivity/custom_hooks.html @@ -0,0 +1,435 @@ + + + + + + Custom Hooks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Custom Hooks

    +

    Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own.

    +

    When writing your hook, you can make a function that accepts cx: &ScopeState as a parameter to accept a scope with any Props.

    +

    Composing Hooks

    +

    To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook.

    +

    For example, if many components need to access an AppSettings struct, you can create a "shortcut" hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn use_settings(cx: &ScopeState) -> &UseSharedState<AppSettings> {
    +    use_shared_state::<AppSettings>(cx).expect("App settings not provided")
    +}
    +}
    +
    +

    Or if you want to wrap a hook that persists reloads with the storage API, you can build on top of the use_ref hook to work with mutable state:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use gloo_storage::{LocalStorage, Storage};
    +use serde::{de::DeserializeOwned, Serialize};
    +
    +/// A persistent storage hook that can be used to store data across application reloads.
    +#[allow(clippy::needless_return)]
    +pub fn use_persistent<T: Serialize + DeserializeOwned + Default + 'static>(
    +    cx: &ScopeState,
    +    // A unique key for the storage entry
    +    key: impl ToString,
    +    // A function that returns the initial value if the storage entry is empty
    +    init: impl FnOnce() -> T,
    +) -> &UsePersistent<T> {
    +    // Use the use_ref hook to create a mutable state for the storage entry
    +    let state = use_ref(cx, move || {
    +        // This closure will run when the hook is created
    +        let key = key.to_string();
    +        let value = LocalStorage::get(key.as_str()).ok().unwrap_or_else(init);
    +        StorageEntry { key, value }
    +    });
    +
    +    // Wrap the state in a new struct with a custom API
    +    // Note: We use use_hook here so that this hook is easier to use in closures in the rsx. Any values with the same lifetime as the ScopeState can be used in the closure without cloning.
    +    cx.use_hook(|| UsePersistent {
    +        inner: state.clone(),
    +    })
    +}
    +
    +struct StorageEntry<T> {
    +    key: String,
    +    value: T,
    +}
    +
    +/// Storage that persists across application reloads
    +pub struct UsePersistent<T: 'static> {
    +    inner: UseRef<StorageEntry<T>>,
    +}
    +
    +impl<T: Serialize + DeserializeOwned + Clone + 'static> UsePersistent<T> {
    +    /// Returns a reference to the value
    +    pub fn get(&self) -> T {
    +        self.inner.read().value.clone()
    +    }
    +
    +    /// Sets the value
    +    pub fn set(&self, value: T) {
    +        let mut inner = self.inner.write();
    +        // Write the new value to local storage
    +        LocalStorage::set(inner.key.as_str(), &value);
    +        inner.value = value;
    +    }
    +}
    +}
    +
    +

    Custom Hook Logic

    +

    You can use cx.use_hook to build your own hooks. In fact, this is what all the standard hooks are built on!

    +

    use_hook accepts a single closure for initializing the hook. It will be only run the first time the component is rendered. The return value of that closure will be used as the value of the hook – Dioxus will take it, and store it for as long as the component is alive. On every render (not just the first one!), you will get a reference to this value.

    +
    +

    Note: You can implement Drop for your hook value – it will be dropped then the component is unmounted (no longer in the UI)

    +
    +

    Inside the initialization closure, you will typically make calls to other cx methods. For example:

    +
      +
    • The use_state hook tracks state in the hook value, and uses cx.schedule_update to make Dioxus re-render the component whenever it changes.
    • +
    +

    Here is a simplified implementation of the use_state hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use std::cell::RefCell;
    +use std::rc::Rc;
    +use std::sync::Arc;
    +
    +#[derive(Clone)]
    +struct UseState<T> {
    +    value: Rc<RefCell<T>>,
    +    update: Arc<dyn Fn()>,
    +}
    +
    +fn my_use_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> &UseState<T> {
    +    cx.use_hook(|| {
    +        // The update function will trigger a re-render in the component cx is attached to
    +        let update = cx.schedule_update();
    +        // Create the initial state
    +        let value = Rc::new(RefCell::new(init()));
    +
    +        UseState { value, update }
    +    })
    +}
    +
    +impl<T: Clone> UseState<T> {
    +    fn get(&self) -> T {
    +        self.value.borrow().clone()
    +    }
    +
    +    fn set(&self, value: T) {
    +        // Update the state
    +        *self.value.borrow_mut() = value;
    +        // Trigger a re-render on the component the state is from
    +        (self.update)();
    +    }
    +}
    +}
    +
    +
      +
    • The use_context hook calls cx.consume_context (which would be expensive to call on every render) to get some context from the scope
    • +
    +

    Here is an implementation of the use_context and use_context_provider hooks:

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> {
    +    cx.use_hook(|| cx.consume_context::<T>()).as_ref()
    +}
    +
    +pub fn use_context_provider<T: 'static + Clone>(cx: &ScopeState, f: impl FnOnce() -> T) -> &T {
    +    cx.use_hook(|| {
    +        let val = f();
    +        // Provide the context state to the scope
    +        cx.provide_context(val.clone());
    +        val
    +    })
    +}
    +
    +}
    +
    +

    Hook Anti-Patterns

    +

    When writing a custom hook, you should avoid the following anti-patterns:

    +
      +
    • !Clone Hooks: To allow hooks to be used within async blocks, the hooks must be Clone. To make a hook clone, you can wrap data in Rc or Arc and avoid lifetimes in hooks.
    • +
    +

    This version of use_state may seem more efficient, but it is not cloneable:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use std::cell::RefCell;
    +use std::rc::Rc;
    +use std::sync::Arc;
    +
    +struct UseState<'a, T> {
    +    value: &'a RefCell<T>,
    +    update: Arc<dyn Fn()>,
    +}
    +
    +fn my_use_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> UseState<T> {
    +    // The update function will trigger a re-render in the component cx is attached to
    +    let update = cx.schedule_update();
    +    // Create the initial state
    +    let value = cx.use_hook(|| RefCell::new(init()));
    +
    +    UseState { value, update }
    +}
    +
    +impl<T: Clone> UseState<'_, T> {
    +    fn get(&self) -> T {
    +        self.value.borrow().clone()
    +    }
    +
    +    fn set(&self, value: T) {
    +        // Update the state
    +        *self.value.borrow_mut() = value;
    +        // Trigger a re-render on the component the state is from
    +        (self.update)();
    +    }
    +}
    +}
    +
    +

    If we try to use this hook in an async block, we will get a compile error:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn FutureComponent(cx: &ScopeState) -> Element {
    +    let my_state = my_use_state(cx, || 0);
    +    cx.spawn({
    +        to_owned![my_state];
    +        async move {
    +            my_state.set(1);
    +        }
    +    });
    +
    +    todo!()
    +}
    +}
    +
    +

    But with the original version, we can use it in an async block:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn FutureComponent(cx: &ScopeState) -> Element {
    +    let my_state = use_state(cx, || 0);
    +    cx.spawn({
    +        to_owned![my_state];
    +        async move {
    +            my_state.set(1);
    +        }
    +    });
    +
    +    todo!()
    +}
    +}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/dynamic_rendering.html b/docs/nightly/guide/en/interactivity/dynamic_rendering.html new file mode 100644 index 000000000..f5088b4ae --- /dev/null +++ b/docs/nightly/guide/en/interactivity/dynamic_rendering.html @@ -0,0 +1,418 @@ + + + + + + Dynamic Rendering + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Dynamic Rendering

    +

    Sometimes you want to render different things depending on the state/props. With Dioxus, just describe what you want to see using Rust control flow – the framework will take care of making the necessary changes on the fly if the state or props change!

    +

    Conditional Rendering

    +

    To render different elements based on a condition, you could use an if-else statement:

    +
    
    +#![allow(unused)]
    +fn main() {
    +if *is_logged_in {
    +    cx.render(rsx! {
    +        "Welcome!"
    +        button {
    +            onclick: move |_| on_log_out.call(()),
    +            "Log Out",
    +        }
    +    })
    +} else {
    +    cx.render(rsx! {
    +        button {
    +            onclick: move |_| on_log_in.call(()),
    +            "Log In",
    +        }
    +    })
    +}
    +}
    +
    +
    +

    You could also use match statements, or any Rust function to conditionally render different things.

    +
    +

    Improving the if-else Example

    +

    You may have noticed some repeated code in the if-else example above. Repeating code like this is both bad for maintainability and performance. Dioxus will skip diffing static elements like the button, but when switching between multiple rsx calls it cannot perform this optimization. For this example either approach is fine, but for components with large parts that are reused between conditionals, it can be more of an issue.

    +

    We can improve this example by splitting up the dynamic parts and inserting them where they are needed.

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    // We only render the welcome message if we are logged in
    +    // You can use if statements in the middle of a render block to conditionally render elements
    +    if *is_logged_in {
    +        // Notice the body of this if statment is rsx code, not an expression
    +        "Welcome!"
    +    }
    +    button {
    +        // depending on the value of `is_logged_in`, we will call a different event handler
    +        onclick: move |_| if *is_logged_in {
    +            on_log_in.call(())
    +        }
    +        else{
    +            on_log_out.call(())
    +        },
    +        if *is_logged_in {
    +            // if we are logged in, the button should say "Log Out"
    +            "Log Out"
    +        } else {
    +            // if we are not logged in, the button should say "Log In"
    +            "Log In"
    +        }
    +    }
    +})
    +}
    +
    +

    Inspecting Element props

    +

    Since Element is a Option<VNode>, components accepting Element as a prop can inspect its contents, and render different things based on that. Example:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
    +    match cx.props.children {
    +        Some(VNode { dynamic_nodes, .. }) => {
    +            todo!("render some stuff")
    +        }
    +        _ => {
    +            todo!("render some other stuff")
    +        }
    +    }
    +}
    +}
    +
    +

    You can't mutate the Element, but if you need a modified version of it, you can construct a new one based on its attributes/children/etc.

    +

    Rendering Nothing

    +

    To render nothing, you can return None from a component. This is useful if you want to conditionally hide something:

    +
    
    +#![allow(unused)]
    +fn main() {
    +if *is_logged_in {
    +    return None;
    +}
    +
    +cx.render(rsx! {
    +    a {
    +        "You must be logged in to comment"
    +    }
    +})
    +}
    +
    +

    This works because the Element type is just an alias for Option<VNode>

    +
    +

    Again, you may use a different method to conditionally return None. For example the boolean's then() function could be used.

    +
    +

    Rendering Lists

    +

    Often, you'll want to render a collection of components. For example, you might want to render a list of all comments on a post.

    +

    For this, Dioxus accepts iterators that produce Elements. So we need to:

    +
      +
    • Get an iterator over all of our items (e.g., if you have a Vec of comments, iterate over it with iter())
    • +
    • .map the iterator to convert each item into a LazyNode using rsx!(...) +
        +
      • Add a unique key attribute to each iterator item
      • +
      +
    • +
    • Include this iterator in the final RSX (or use it inline)
    • +
    +

    Example: suppose you have a list of comments you want to render. Then, you can render them like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let comment_field = use_state(cx, String::new);
    +let mut next_id = use_state(cx, || 0);
    +let comments = use_ref(cx, Vec::<Comment>::new);
    +
    +let comments_lock = comments.read();
    +let comments_rendered = comments_lock.iter().map(|comment| {
    +    rsx!(CommentComponent {
    +        key: "{comment.id}",
    +        comment: comment.clone(),
    +    })
    +});
    +
    +cx.render(rsx!(
    +    form {
    +        onsubmit: move |_| {
    +            comments.write().push(Comment {
    +                content: comment_field.get().clone(),
    +                id: *next_id.get(),
    +            });
    +            next_id += 1;
    +
    +            comment_field.set(String::new());
    +        },
    +        input {
    +            value: "{comment_field}",
    +            oninput: |event| comment_field.set(event.value.clone()),
    +        }
    +        input {
    +            r#type: "submit",
    +        }
    +    },
    +    comments_rendered,
    +))
    +}
    +
    +

    Inline for loops

    +

    Because of how common it is to render a list of items, Dioxus provides a shorthand for this. Instead of using .iter, .map, and rsx, you can use a for` loop with a body of rsx code:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let comment_field = use_state(cx, String::new);
    +let mut next_id = use_state(cx, || 0);
    +let comments = use_ref(cx, Vec::<Comment>::new);
    +
    +cx.render(rsx!(
    +    form {
    +        onsubmit: move |_| {
    +            comments.write().push(Comment {
    +                content: comment_field.get().clone(),
    +                id: *next_id.get(),
    +            });
    +            next_id += 1;
    +
    +            comment_field.set(String::new());
    +        },
    +        input {
    +            value: "{comment_field}",
    +            oninput: |event| comment_field.set(event.value.clone()),
    +        }
    +        input {
    +            r#type: "submit",
    +        }
    +    },
    +    for comment in &*comments.read() {
    +        // Notice the body of this for loop is rsx code, not an expression
    +        CommentComponent {
    +            key: "{comment.id}",
    +            comment: comment.clone(),
    +        }
    +    }
    +))
    +}
    +
    +

    The key Attribute

    +

    Every time you re-render your list, Dioxus needs to keep track of which items go where to determine what updates need to be made to the UI.

    +

    For example, suppose the CommentComponent had some state – e.g. a field where the user typed in a reply. If the order of comments suddenly changes, Dioxus needs to correctly associate that state with the same comment – otherwise, the user will end up replying to a different comment!

    +

    To help Dioxus keep track of list items, we need to associate each item with a unique key. In the example above, we dynamically generated the unique key. In real applications, it's more likely that the key will come from e.g. a database ID. It doesn't matter where you get the key from, as long as it meets the requirements:

    +
      +
    • Keys must be unique in a list
    • +
    • The same item should always get associated with the same key
    • +
    • Keys should be relatively small (i.e. converting the entire Comment structure to a String would be a pretty bad key) so they can be compared efficiently
    • +
    +

    You might be tempted to use an item's index in the list as its key. That’s what Dioxus will use if you don’t specify a key at all. This is only acceptable if you can guarantee that the list is constant – i.e., no re-ordering, additions, or deletions.

    +
    +

    Note that if you pass the key to a component you've made, it won't receive the key as a prop. It’s only used as a hint by Dioxus itself. If your component needs an ID, you have to pass it as a separate prop.

    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/event_handlers.html b/docs/nightly/guide/en/interactivity/event_handlers.html new file mode 100644 index 000000000..61d7a540c --- /dev/null +++ b/docs/nightly/guide/en/interactivity/event_handlers.html @@ -0,0 +1,316 @@ + + + + + + Event Listeners + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Event Handlers

    +

    Event handlers are used to respond to user actions. For example, an event handler could be triggered when the user clicks, scrolls, moves the mouse, or types a character.

    +

    Event handlers are attached to elements. For example, we usually don't care about all the clicks that happen within an app, only those on a particular button.

    +

    Event handlers are similar to regular attributes, but their name usually starts with on- and they accept closures as values. The closure will be called whenever the event it listens for is triggered and will be passed that event.

    +

    For example, to handle clicks on an element, we can specify an onclick handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    button {
    +        onclick: move |event| println!("Clicked! Event: {event:?}"),
    +        "click me!"
    +    }
    +})
    +}
    +
    +

    The Event object

    +

    Event handlers receive an Event object containing information about the event. Different types of events contain different types of data. For example, mouse-related events contain MouseData, which tells you things like where the mouse was clicked and what mouse buttons were used.

    +

    In the example above, this event data was logged to the terminal:

    +
    Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }
    +Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }
    +
    +

    To learn what the different event types for HTML provide, read the events module docs.

    +

    Event propagation

    +

    Some events will trigger first on the element the event originated at upward. For example, a click event on a button inside a div would first trigger the button's event listener and then the div's event listener.

    +
    +

    For more information about event propigation see the mdn docs on event bubling

    +
    +

    If you want to prevent this behavior, you can call stop_propagation() on the event:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    div {
    +        onclick: move |_event| {},
    +        "outer",
    +        button {
    +            onclick: move |event| {
    +                // now, outer won't be triggered
    +                event.stop_propagation();
    +            },
    +            "inner"
    +        }
    +    }
    +})
    +}
    +
    +

    Prevent Default

    +

    Some events have a default behavior. For keyboard events, this might be entering the typed character. For mouse events, this might be selecting some text.

    +

    In some instances, might want to avoid this default behavior. For this, you can add the prevent_default attribute with the name of the handler whose default behavior you want to stop. This attribute can be used for multiple handlers using their name separated by spaces:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    input {
    +        prevent_default: "oninput onclick",
    +    }
    +})
    +}
    +
    +

    Any event handlers will still be called.

    +
    +

    Normally, in React or JavaScript, you'd call "preventDefault" on the event in the callback. Dioxus does not currently support this behavior. Note: this means you cannot conditionally prevent default behavior based on the data in the event.

    +
    +

    Handler Props

    +

    Sometimes, you might want to make a component that accepts an event handler. A simple example would be a FancyButton component, which accepts an on_click handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +pub struct FancyButtonProps<'a> {
    +    on_click: EventHandler<'a, MouseEvent>,
    +}
    +
    +pub fn FancyButton<'a>(cx: Scope<'a, FancyButtonProps<'a>>) -> Element<'a> {
    +    cx.render(rsx!(button {
    +        class: "fancy-button",
    +        onclick: move |evt| cx.props.on_click.call(evt),
    +        "click me pls."
    +    }))
    +}
    +}
    +
    +

    Then, you can use it like any other handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +    cx.render(rsx! {
    +        FancyButton {
    +            on_click: move |event| println!("Clicked! {event:?}")
    +        }
    +    })
    +}
    +
    +
    +

    Note: just like any other attribute, you can name the handlers anything you want! Though they must start with on, for the prop to be automatically turned into an EventHandler at the call site.

    +

    You can also put custom data in the event, rather than e.g. MouseData

    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/hooks.html b/docs/nightly/guide/en/interactivity/hooks.html new file mode 100644 index 000000000..a16179255 --- /dev/null +++ b/docs/nightly/guide/en/interactivity/hooks.html @@ -0,0 +1,388 @@ + + + + + + Hooks & Component State + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Hooks and Component State

    +

    So far our components have had no state like a normal rust functions. However, in a UI component, it is often useful to have stateful functionality to build user interactions. For example, you might want to track whether the user has opened a drop-down, and render different things accordingly.

    +

    Hooks allow us to create state in our components. Hooks are Rust functions that take a reference to ScopeState (in a component, you can pass cx), and provide you with functionality and state.

    +

    use_state Hook

    +

    use_state is one of the simplest hooks.

    +
      +
    • You provide a closure that determines the initial value
    • +
    • use_state gives you the current value, and a way to update it by setting it to something else
    • +
    • When the value updates, use_state makes the component re-render, and provides you with the new value
    • +
    +

    For example, you might have seen the counter example, in which state (a number) is tracked using the use_state hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    // count will be initialized to 0 the first time the component is rendered
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "High-Five counter: {count}" }
    +        button {
    +            onclick: move |_| {
    +                // changing the count will cause the component to re-render
    +                count += 1
    +            },
    +            "Up high!"
    +        }
    +        button {
    +            onclick: move |_| {
    +                // changing the count will cause the component to re-render
    +                count -= 1
    +            },
    +            "Down low!"
    +        }
    +    ))
    +}
    +}
    +
    +

    Screenshot: counter app

    +

    Every time the component's state changes, it re-renders, and the component function is called, so you can describe what you want the new UI to look like. You don't have to worry about "changing" anything – just describe what you want in terms of the state, and Dioxus will take care of the rest!

    +
    +

    use_state returns your value wrapped in a smart pointer of type UseState. This is why you can both read the value and update it, even within an event handler.

    +
    +

    You can use multiple hooks in the same component if you want:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let mut count_a = use_state(cx, || 0);
    +    let mut count_b = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "Counter_a: {count_a}" }
    +        button { onclick: move |_| count_a += 1, "a++" }
    +        button { onclick: move |_| count_a -= 1, "a--" }
    +        h1 { "Counter_b: {count_b}" }
    +        button { onclick: move |_| count_b += 1, "b++" }
    +        button { onclick: move |_| count_b -= 1, "b--" }
    +    ))
    +}
    +}
    +
    +

    Screenshot: app with two counters

    +

    Rules of Hooks

    +

    The above example might seem a bit magic, since Rust functions are typically not associated with state. Dioxus allows hooks to maintain state across renders through a reference to ScopeState, which is why you must pass &cx to them.

    +

    But how can Dioxus differentiate between multiple hooks in the same component? As you saw in the second example, both use_state functions were called with the same parameters, so how come they can return different things when the counters are different?

    +
    
    +#![allow(unused)]
    +fn main() {
    +    let mut count_a = use_state(cx, || 0);
    +    let mut count_b = use_state(cx, || 0);
    +}
    +
    +

    This is only possible because the two hooks are always called in the same order, so Dioxus knows which is which. Because the order you call hooks matters, you must follow certain rules when using hooks:

    +
      +
    1. Hooks may be only used in components or other hooks (we'll get to that later)
    2. +
    3. On every call to the component function +
        +
      1. The same hooks must be called (except in the case of early returns, as explained later in the Error Handling chapter)
      2. +
      3. In the same order
      4. +
      +
    4. +
    5. Hooks name's should start with use_ so you don't accidentally confuse them with regular functions
    6. +
    +

    These rules mean that there are certain things you can't do with hooks:

    +

    No Hooks in Conditionals

    +
    
    +#![allow(unused)]
    +fn main() {
    +// ❌ don't call hooks in conditionals!
    +// We must ensure that the same hooks will be called every time
    +// But `if` statements only run if the conditional is true!
    +// So we might violate rule 2.
    +if you_are_happy && you_know_it {
    +    let something = use_state(cx, || "hands");
    +    println!("clap your {something}")
    +}
    +
    +// ✅ instead, *always* call use_state
    +// You can put other stuff in the conditional though
    +let something = use_state(cx, || "hands");
    +if you_are_happy && you_know_it {
    +    println!("clap your {something}")
    +}
    +}
    +
    +

    No Hooks in Closures

    +
    
    +#![allow(unused)]
    +fn main() {
    +// ❌ don't call hooks inside closures!
    +// We can't guarantee that the closure, if used, will be called in the same order every time
    +let _a = || {
    +    let b = use_state(cx, || 0);
    +    b.get()
    +};
    +
    +// ✅ instead, move hook `b` outside
    +let b = use_state(cx, || 0);
    +let _a = || b.get();
    +}
    +
    +

    No Hooks in Loops

    +
    
    +#![allow(unused)]
    +fn main() {
    +// `names` is a Vec<&str>
    +
    +// ❌ Do not use hooks in loops!
    +// In this case, if the length of the Vec changes, we break rule 2
    +for _name in &names {
    +    let is_selected = use_state(cx, || false);
    +    println!("selected: {is_selected}");
    +}
    +
    +// ✅ Instead, use a hashmap with use_ref
    +let selection_map = use_ref(cx, HashMap::<&str, bool>::new);
    +
    +for name in &names {
    +    let is_selected = selection_map.read()[name];
    +    println!("selected: {is_selected}");
    +}
    +}
    +
    +

    use_ref Hook

    +

    use_state is great for tracking simple values. However, you may notice in the UseState API that the only way to modify its value is to replace it with something else (e.g., by calling set, or through one of the +=, -= operators). This works well when it is cheap to construct a value (such as any primitive). But what if you want to maintain more complex data in the components state?

    +

    For example, suppose we want to maintain a Vec of values. If we stored it with use_state, the only way to add a new value to the list would be to create a new Vec with the additional value, and put it in the state. This is expensive! We want to modify the existing Vec instead.

    +

    Thankfully, there is another hook for that, use_ref! It is similar to use_state, but it lets you get a mutable reference to the contained data.

    +

    Here's a simple example that keeps a list of events in a use_ref. We can acquire write access to the state with .with_mut(), and then just .push a new value to the state:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let list = use_ref(cx, Vec::new);
    +
    +    cx.render(rsx!(
    +        p { "Current list: {list.read():?}" }
    +        button {
    +            onclick: move |event| {
    +                list.with_mut(|list| list.push(event));
    +            },
    +            "Click me!"
    +        }
    +    ))
    +}
    +}
    +
    +
    +

    The return values of use_state and use_ref (UseState and UseRef, respectively) are in some ways similar to Cell and RefCell – they provide interior mutability. However, these Dioxus wrappers also ensure that the component gets re-rendered whenever you change the state.

    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/images/counter.png b/docs/nightly/guide/en/interactivity/images/counter.png new file mode 100644 index 0000000000000000000000000000000000000000..dd89cadef3ab7794d1f77b08350b8a2cad434b72 GIT binary patch literal 11368 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 O00kLk=_*O1;Qs=kxyf1p literal 0 HcmV?d00001 diff --git a/docs/nightly/guide/en/interactivity/images/counter_two_state.png b/docs/nightly/guide/en/interactivity/images/counter_two_state.png new file mode 100644 index 0000000000000000000000000000000000000000..4f77942a20ab23ea01784871c7bc977a2baec4a5 GIT binary patch literal 14503 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

    Xr+Mb0o6&U|y=x|mJQEkCNwLvd|7x7mswPA5 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 + + + + + Interactivity + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + +
    + +
    + + + + + + + + +
    +
    +

    Interactivity

    +

    So far, we've learned how to describe the structure and properties of our user interfaces. However, most interfaces need to be interactive in order to be useful. In this chapter, we describe how to make a Dioxus app that responds to the user.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/router.html b/docs/nightly/guide/en/interactivity/router.html new file mode 100644 index 000000000..01fe94b39 --- /dev/null +++ b/docs/nightly/guide/en/interactivity/router.html @@ -0,0 +1,296 @@ + + + + + + Routing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Router

    +

    In many of your apps, you'll want to have different "scenes". For a webpage, these scenes might be the different webpages with their own content. For a desktop app, these scenes might be different views in your app.

    +

    To unify these platforms, Dioxus provides a first-party solution for scene management called Dioxus Router.

    +

    What is it?

    +

    For an app like the Dioxus landing page (https://dioxuslabs.com), we want to have several different scenes:

    +
      +
    • Homepage
    • +
    • Blog
    • +
    +

    Each of these scenes is independent – we don't want to render both the homepage and blog at the same time.

    +

    The Dioxus router makes it easy to create these scenes. To make sure we're using the router, add the dioxus-router package to your Cargo.toml.

    +
    cargo add dioxus-router
    +
    +

    Using the router

    +

    Unlike other routers in the Rust ecosystem, our router is built declaratively. This makes it possible to compose our app layout simply by arranging components.

    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    // All of our routes will be rendered inside this Router component
    +    Router {
    +        // if the current location is "/home", render the Home component
    +        Route { to: "/home", Home {} }
    +        // if the current location is "/blog", render the Blog component
    +        Route { to: "/blog", Blog {} }
    +    }
    +}
    +}
    +
    +

    Whenever we visit this app, we will get either the Home component or the Blog component rendered depending on which route we enter at. If neither of these routes match the current location, then nothing will render.

    +

    We can fix this one of two ways:

    +
      +
    • A fallback 404 page
    • +
    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Router {
    +        Route { to: "/home", Home {} }
    +        Route { to: "/blog", Blog {} }
    +        //  if the current location doesn't match any of the above routes, render the NotFound component
    +        Route { to: "", NotFound {} }
    +    }
    +}
    +}
    +
    +
      +
    • Redirect 404 to home
    • +
    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Router {
    +        Route { to: "/home", Home {} }
    +        Route { to: "/blog", Blog {} }
    +        //  if the current location doesn't match any of the above routes, redirect to "/home"
    +        Redirect { from: "", to: "/home" }
    +    }
    +}
    +}
    +
    + +

    For our app to navigate these routes, we can provide clickable elements called Links. These simply wrap <a> elements that, when clicked, navigate the app to the given location.

    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Link {
    +        to: "/home",
    +        "Go home!"
    +    }
    +}
    +}
    +
    +

    More reading

    +

    This page is just a very brief overview of the router. For more information, check out the router book or some of the router examples.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/sharing_state.html b/docs/nightly/guide/en/interactivity/sharing_state.html new file mode 100644 index 000000000..06dfe8073 --- /dev/null +++ b/docs/nightly/guide/en/interactivity/sharing_state.html @@ -0,0 +1,392 @@ + + + + + + Sharing State + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Sharing State

    +

    Often, multiple components need to access the same state. Depending on your needs, there are several ways to implement this.

    +

    Lifting State

    +

    One approach to share state between components is to "lift" it up to the nearest common ancestor. This means putting the use_state hook in a parent component, and passing the needed values down as props.

    +

    Suppose we want to build a meme editor. We want to have an input to edit the meme caption, but also a preview of the meme with the caption. Logically, the meme and the input are 2 separate components, but they need access to the same state (the current caption).

    +
    +

    Of course, in this simple example, we could write everything in one component – but it is better to split everything out in smaller components to make the code more reusable, maintainable, and performant (this is even more important for larger, complex apps).

    +
    +

    We start with a Meme component, responsible for rendering a meme with a given caption:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[inline_props]
    +fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
    +    let container_style = r#"
    +        position: relative;
    +        width: fit-content;
    +    "#;
    +
    +    let caption_container_style = r#"
    +        position: absolute;
    +        bottom: 0;
    +        left: 0;
    +        right: 0;
    +        padding: 16px 8px;
    +    "#;
    +
    +    let caption_style = r"
    +        font-size: 32px;
    +        margin: 0;
    +        color: white;
    +        text-align: center;
    +    ";
    +
    +    cx.render(rsx!(
    +        div {
    +            style: "{container_style}",
    +            img {
    +                src: "https://i.imgflip.com/2zh47r.jpg",
    +                height: "500px",
    +            },
    +            div {
    +                style: "{caption_container_style}",
    +                p {
    +                    style: "{caption_style}",
    +                    "{caption}"
    +                }
    +            }
    +        }
    +    ))
    +}
    +}
    +
    +
    +

    Note that the Meme component is unaware where the caption is coming from – it could be stored in use_state, use_ref, or a constant. This ensures that it is very reusable – the same component can be used for a meme gallery without any changes!

    +
    +

    We also create a caption editor, completely decoupled from the meme. The caption editor must not store the caption itself – otherwise, how will we provide it to the Meme component? Instead, it should accept the current caption as a prop, as well as an event handler to delegate input events to:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[inline_props]
    +fn CaptionEditor<'a>(
    +    cx: Scope<'a>,
    +    caption: &'a str,
    +    on_input: EventHandler<'a, FormEvent>,
    +) -> Element<'a> {
    +    let input_style = r"
    +        border: none;
    +        background: cornflowerblue;
    +        padding: 8px 16px;
    +        margin: 0;
    +        border-radius: 4px;
    +        color: white;
    +    ";
    +
    +    cx.render(rsx!(input {
    +        style: "{input_style}",
    +        value: "{caption}",
    +        oninput: move |event| on_input.call(event),
    +    }))
    +}
    +}
    +
    +

    Finally, a third component will render the other two as children. It will be responsible for keeping the state and passing down the relevant props.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn MemeEditor(cx: Scope) -> Element {
    +    let container_style = r"
    +        display: flex;
    +        flex-direction: column;
    +        gap: 16px;
    +        margin: 0 auto;
    +        width: fit-content;
    +    ";
    +
    +    let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
    +
    +    cx.render(rsx! {
    +        div {
    +            style: "{container_style}",
    +            h1 { "Meme Editor" },
    +            Meme {
    +                caption: caption,
    +            },
    +            CaptionEditor {
    +                caption: caption,
    +                on_input: move |event: FormEvent| {caption.set(event.value.clone());},
    +            },
    +        }
    +    })
    +}
    +}
    +
    +

    Meme Editor Screenshot: An old plastic skeleton sitting on a park bench. Caption: "me waiting for a language feature"

    +

    Using Context

    +

    Sometimes, some state needs to be shared between multiple components far down the tree, and passing it down through props is very inconvenient.

    +

    Suppose now that we want to implement a dark mode toggle for our app. To achieve this, we will make every component select styling depending on whether dark mode is enabled or not.

    +
    +

    Note: we're choosing this approach for the sake of an example. There are better ways to implement dark mode (e.g. using CSS variables). Let's pretend CSS variables don't exist – welcome to 2013!

    +
    +

    Now, we could write another use_state in the top component, and pass is_dark_mode down to every component through props. But think about what will happen as the app grows in complexity – almost every component that renders any CSS is going to need to know if dark mode is enabled or not – so they'll all need the same dark mode prop. And every parent component will need to pass it down to them. Imagine how messy and verbose that would get, especially if we had components several levels deep!

    +

    Dioxus offers a better solution than this "prop drilling" – providing context. The use_context_provider hook is similar to use_ref, but it makes it available through use_context for all children components.

    +

    First, we have to create a struct for our dark mode configuration:

    +
    
    +#![allow(unused)]
    +fn main() {
    +struct DarkMode(bool);
    +}
    +
    +

    Now, in a top-level component (like App), we can provide the DarkMode context to all children components:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use_shared_state_provider(cx, || DarkMode(false));
    +}
    +
    +

    As a result, any child component of App (direct or not), can access the DarkMode context.

    +
    
    +#![allow(unused)]
    +fn main() {
    +let dark_mode_context = use_shared_state::<DarkMode>(cx);
    +}
    +
    +
    +

    use_context returns Option<UseSharedState<DarkMode>> here. If the context has been provided, the value is Some(UseSharedState<DarkMode>), which you can call .read or .write on, similarly to UseRef. Otherwise, the value is None.

    +
    +

    For example, here's how we would implement the dark mode toggle, which both reads the context (to determine what color it should render) and writes to it (to toggle dark mode):

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub fn DarkModeToggle(cx: Scope) -> Element {
    +    let dark_mode = use_shared_state::<DarkMode>(cx).unwrap();
    +
    +    let style = if dark_mode.read().0 {
    +        "color:white"
    +    } else {
    +        ""
    +    };
    +
    +    cx.render(rsx!(label {
    +        style: "{style}",
    +        "Dark Mode",
    +        input {
    +            r#type: "checkbox",
    +            oninput: move |event| {
    +                let is_enabled = event.value == "true";
    +                dark_mode.write().0 = is_enabled;
    +            },
    +        },
    +    }))
    +}
    +}
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/interactivity/user_input.html b/docs/nightly/guide/en/interactivity/user_input.html new file mode 100644 index 000000000..2a7a4b793 --- /dev/null +++ b/docs/nightly/guide/en/interactivity/user_input.html @@ -0,0 +1,270 @@ + + + + + + User Input + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    User Input

    +

    Interfaces often need to provide a way to input data: e.g. text, numbers, checkboxes, etc. In Dioxus, there are two ways you can work with user input.

    +

    Controlled Inputs

    +

    With controlled inputs, you are directly in charge of the state of the input. This gives you a lot of flexibility, and makes it easy to keep things in sync. For example, this is how you would create a controlled text input:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let name = use_state(cx, || "bob".to_string());
    +
    +    cx.render(rsx! {
    +        input {
    +            // we tell the component what to render
    +            value: "{name}",
    +            // and what to do when the value changes
    +            oninput: move |evt| name.set(evt.value.clone()),
    +        }
    +    })
    +}
    +}
    +
    +

    Notice the flexibility – you can:

    +
      +
    • Also display the same contents in another element, and they will be in sync
    • +
    • Transform the input every time it is modified (e.g. to make sure it is upper case)
    • +
    • Validate the input every time it changes
    • +
    • Have custom logic happening when the input changes (e.g. network request for autocompletion)
    • +
    • Programmatically change the value (e.g. a "randomize" button that fills the input with nonsense)
    • +
    +

    Uncontrolled Inputs

    +

    As an alternative to controlled inputs, you can simply let the platform keep track of the input values. If we don't tell a HTML input what content it should have, it will be editable anyway (this is built into the browser). This approach can be more performant, but less flexible. For example, it's harder to keep the input in sync with another element.

    +

    Since you don't necessarily have the current value of the uncontrolled input in state, you can access it either by listening to oninput events (similarly to controlled components), or, if the input is part of a form, you can access the form data in the form events (e.g. oninput or onsubmit):

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        form {
    +            onsubmit: move |event| {
    +                println!("Submitted! {event:?}")
    +            },
    +            input { name: "name", },
    +            input { name: "age", },
    +            input { name: "date", },
    +            input { r#type: "submit", },
    +        }
    +    })
    +}
    +}
    +
    +
    Submitted! UiEvent { data: FormData { value: "", values: {"age": "very old", "date": "1966", "name": "Fred"} } }
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/lib.rs b/docs/nightly/guide/en/lib.rs new file mode 100644 index 000000000..97cda56a8 --- /dev/null +++ b/docs/nightly/guide/en/lib.rs @@ -0,0 +1 @@ +// empty (we only need this crate for the examples) diff --git a/docs/nightly/guide/en/mark.min.js b/docs/nightly/guide/en/mark.min.js new file mode 100644 index 000000000..163623188 --- /dev/null +++ b/docs/nightly/guide/en/mark.min.js @@ -0,0 +1,7 @@ +/*!*************************************************** +* mark.js v8.11.1 +* https://markjs.io/ +* Copyright (c) 2014–2018, Julian Kühnel +* Released under the MIT license https://git.io/vwTVl +*****************************************************/ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function e(n){t(this,e),this.opt=r({},{diacritics:!0,synonyms:{},accuracy:"partially",caseSensitive:!1,ignoreJoiners:!1,ignorePunctuation:[],wildcards:"disabled"},n)}return n(e,[{key:"create",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),new RegExp(e,"gm"+(this.opt.caseSensitive?"":"i"))}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynonyms(a)+"|"+this.processSynonyms(s)+")"+r))}return e}},{key:"processSynonyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapGroups",value:function(e,t,n,r){return r((e=this.wrapRangeInTextNode(e,t,t+n)).previousSibling),e}},{key:"separateGroups",value:function(e,t,n,r,i){for(var o=t.length,a=1;a-1&&r(t[a],e)&&(e=this.wrapGroups(e,s,t[a].length,i))}return e}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];){if(o.opt.separateGroups)t=o.separateGroups(t,i,a,n,r);else{if(!n(i[a],t))continue;var s=i.index;if(0!==a)for(var c=1;c=n[1]?(e.length>n[1]&&(r="invalid"),n.shift(),n.shift(),this.next=n.shift()):this.next="",r},regex:/"#*/,next:"start"},{defaultToken:"string.quoted.raw.source.rust"}]},{token:"string.quoted.double.source.rust",regex:'"',push:[{token:"string.quoted.double.source.rust",regex:'"',next:"pop"},{token:"constant.character.escape.source.rust",regex:s},{defaultToken:"string.quoted.double.source.rust"}]},{token:["keyword.source.rust","text","entity.name.function.source.rust"],regex:"\\b(fn)(\\s+)((?:r#)?[a-zA-Z_][a-zA-Z0-9_]*)"},{token:"support.constant",regex:"\\b[a-zA-Z_][\\w\\d]*::"},{token:"keyword.source.rust",regex:"\\b(?:abstract|alignof|as|become|box|break|catch|continue|const|crate|default|do|dyn|else|enum|extern|for|final|if|impl|in|let|loop|macro|match|mod|move|mut|offsetof|override|priv|proc|pub|pure|ref|return|self|sizeof|static|struct|super|trait|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\\b"},{token:"storage.type.source.rust",regex:"\\b(?:Self|isize|usize|char|bool|u8|u16|u32|u64|u128|f16|f32|f64|i8|i16|i32|i64|i128|str|option|either|c_float|c_double|c_void|FILE|fpos_t|DIR|dirent|c_char|c_schar|c_uchar|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|size_t|ptrdiff_t|clock_t|time_t|c_longlong|c_ulonglong|intptr_t|uintptr_t|off_t|dev_t|ino_t|pid_t|mode_t|ssize_t)\\b"},{token:"variable.language.source.rust",regex:"\\bself\\b"},{token:"comment.line.doc.source.rust",regex:"//!.*$"},{token:"comment.line.double-dash.source.rust",regex:"//.*$"},{token:"comment.start.block.source.rust",regex:"/\\*",stateName:"comment",push:[{token:"comment.start.block.source.rust",regex:"/\\*",push:"comment"},{token:"comment.end.block.source.rust",regex:"\\*/",next:"pop"},{defaultToken:"comment.block.source.rust"}]},{token:"keyword.operator",regex:/\$|[-=]>|[-+%^=!&|<>]=?|[*/](?![*/])=?/},{token:"punctuation.operator",regex:/[?:,;.]/},{token:"paren.lparen",regex:/[\[({]/},{token:"paren.rparen",regex:/[\])}]/},{token:"constant.language.source.rust",regex:"\\b(?:true|false|Some|None|Ok|Err)\\b"},{token:"support.constant.source.rust",regex:"\\b(?:EXIT_FAILURE|EXIT_SUCCESS|RAND_MAX|EOF|SEEK_SET|SEEK_CUR|SEEK_END|_IOFBF|_IONBF|_IOLBF|BUFSIZ|FOPEN_MAX|FILENAME_MAX|L_tmpnam|TMP_MAX|O_RDONLY|O_WRONLY|O_RDWR|O_APPEND|O_CREAT|O_EXCL|O_TRUNC|S_IFIFO|S_IFCHR|S_IFBLK|S_IFDIR|S_IFREG|S_IFMT|S_IEXEC|S_IWRITE|S_IREAD|S_IRWXU|S_IXUSR|S_IWUSR|S_IRUSR|F_OK|R_OK|W_OK|X_OK|STDIN_FILENO|STDOUT_FILENO|STDERR_FILENO)\\b"},{token:"meta.preprocessor.source.rust",regex:"\\b\\w\\(\\w\\)*!|#\\[[\\w=\\(\\)_]+\\]\\b"},{token:"constant.numeric.source.rust",regex:/\b(?:0x[a-fA-F0-9_]+|0o[0-7_]+|0b[01_]+|[0-9][0-9_]*(?!\.))(?:[iu](?:size|8|16|32|64|128))?\b/},{token:"constant.numeric.source.rust",regex:/\b(?:[0-9][0-9_]*)(?:\.[0-9][0-9_]*)?(?:[Ee][+-][0-9][0-9_]*)?(?:f32|f64)?\b/}]},this.normalizeRules()};o.metaData={fileTypes:["rs","rc"],foldingStartMarker:"^.*\\bfn\\s*(\\w+\\s*)?\\([^\\)]*\\)(\\s*\\{[^\\}]*)?\\s*$",foldingStopMarker:"^\\s*\\}",name:"Rust",scopeName:"source.rust"},r.inherits(o,i),t.RustHighlightRules=o}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/rust",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/rust_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./rust_highlight_rules").RustHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/",nestable:!0},this.$quotes={'"':'"'},this.$id="ace/mode/rust"}.call(u.prototype),t.Mode=u}); (function() { + ace.require(["ace/mode/rust"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); diff --git a/docs/nightly/guide/en/print.html b/docs/nightly/guide/en/print.html new file mode 100644 index 000000000..f87ff3796 --- /dev/null +++ b/docs/nightly/guide/en/print.html @@ -0,0 +1,4483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Introduction

    +

    dioxuslogo

    +

    Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust. This guide will help you get started with writing Dioxus apps for the Web, Desktop, Mobile, and more.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    ))
    +}
    +}
    +
    +

    Dioxus is heavily inspired by React. If you know React, getting started with Dioxus will be a breeze.

    +
    +

    This guide assumes you already know some Rust! If not, we recommend reading the book to learn Rust first.

    +
    +

    Features

    +
      +
    • Desktop apps running natively (no Electron!) in less than 10 lines of code.
    • +
    • Incredibly ergonomic and powerful state management.
    • +
    • Comprehensive inline documentation – hover and guides for all HTML elements, listeners, and events.
    • +
    • Extremely memory efficient – 0 global allocations for steady-state components.
    • +
    • Multi-channel asynchronous scheduler for first-class async support.
    • +
    • And more! Read the full release post.
    • +
    +

    Multiplatform

    +

    Dioxus is a portable toolkit, meaning the Core implementation can run anywhere with no platform-dependent linking. Unlike many other Rust frontend toolkits, Dioxus is not intrinsically linked to WebSys. In fact, every element and event listener can be swapped out at compile time. By default, Dioxus ships with the html feature enabled, but this can be disabled depending on your target renderer.

    +

    Right now, we have several 1st-party renderers:

    +
      +
    • WebSys (for WASM): Great support
    • +
    • Tao/Tokio (for Desktop apps): Good support
    • +
    • Tao/Tokio (for Mobile apps): Poor support
    • +
    • SSR (for generating static markup)
    • +
    • TUI/Rink (for terminal-based apps): Experimental
    • +
    +

    Stability

    +

    Dioxus has not reached a stable release yet.

    +

    Web: Since the web is a fairly mature platform, we expect there to be very little API churn for web-based features.

    +

    Desktop: APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.

    +

    SSR: We don't expect the SSR API to change drastically in the future.

    +

    Getting Started

    +

    This section will help you set up your Dioxus project!

    +

    Prerequisites

    +

    An Editor

    +

    Dioxus integrates very well with the Rust-Analyzer LSP plugin which will provide appropriate syntax highlighting, code navigation, folding, and more.

    +

    Rust

    +

    Head over to https://rust-lang.org and install the Rust compiler.

    +

    We strongly recommend going through the official Rust book completely. However, we hope that a Dioxus app can serve as a great first Rust project. With Dioxus, you'll learn about:

    +
      +
    • Error handling
    • +
    • Structs, Functions, Enums
    • +
    • Closures
    • +
    • Macros
    • +
    +

    We've put a lot of care into making Dioxus syntax familiar and easy to understand, so you won't need deep knowledge of async, lifetimes, or smart pointers until you start building complex Dioxus apps.

    +

    Setup Guides

    +

    Dioxus supports multiple platforms. Choose the platform you want to target below to get platform-specific setup instructions:

    +
      +
    • Web: runs in the browser through WebAssembly
    • +
    • Server Side Rendering: renders to HTML text on the server
    • +
    • Liveview: runs on the server, renders in the browser using WebSockets
    • +
    • Desktop: runs in a web view on desktop
    • +
    • Mobile: runs in a web view on mobile
    • +
    • Terminal UI: renders text-based graphics in the terminal
    • +
    +

    Desktop Overview

    +

    Build a standalone native desktop app that looks and feels the same across operating systems.

    +

    Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory.

    +

    Examples:

    + +

    File ExplorerExample

    +

    Support

    +

    The desktop is a powerful target for Dioxus but is currently limited in capability when compared to the Web platform. Currently, desktop apps are rendered with the platform's WebView library, but your Rust code is running natively on a native thread. This means that browser APIs are not available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs are accessible, so streaming, WebSockets, filesystem, etc are all viable APIs. In the future, we plan to move to a custom web renderer-based DOM renderer with WGPU integrations.

    +

    Dioxus Desktop is built off Tauri. Right now there aren't any Dioxus abstractions over the menubar, handling, etc, so you'll want to leverage Tauri – mostly Wry and Tao) directly.

    +

    Getting started

    +

    Platform-Specific Dependencies

    +

    Dioxus desktop renders through a web view. Depending on your platform, you might need to install some dependancies.

    +

    Windows

    +

    Windows Desktop apps depend on WebView2 – a library that should be installed in all modern Windows distributions. If you have Edge installed, then Dioxus will work fine. If you don't have Webview2, then you can install it through Microsoft. MS provides 3 options:

    +
      +
    1. A tiny "evergreen" bootstrapper that fetches an installer from Microsoft's CDN
    2. +
    3. A tiny installer that fetches Webview2 from Microsoft's CDN
    4. +
    5. A statically linked version of Webview2 in your final binary for offline users
    6. +
    +

    For development purposes, use Option 1.

    +

    Linux

    +

    Webview Linux apps require WebkitGtk. When distributing, this can be part of your dependency tree in your .rpm or .deb. However, likely, your users will already have WebkitGtk.

    +
    sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
    +
    +

    When using Debian/bullseye libappindicator3-dev is no longer available but replaced by libayatana-appindicator3-dev.

    +
    # on Debian/bullseye use:
    +sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
    +
    +

    If you run into issues, make sure you have all the basics installed, as outlined in the Tauri docs.

    +

    MacOS

    +

    Currently – everything for macOS is built right in! However, you might run into an issue if you're using nightly Rust due to some permissions issues in our Tao dependency (which have been resolved but not published).

    +

    Creating a Project

    +

    Create a new crate:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the desktop renderer as dependencies (this will edit your Cargo.toml):

    +
    cargo add dioxus
    +cargo add dioxus-desktop
    +
    +

    Edit your main.rs:

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the dioxus app in a webview
    +    dioxus_desktop::launch(App);
    +}
    +
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    +

    Web

    +

    Build single-page applications that run in the browser with Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the dioxus and dioxus-web crates.

    +

    A build of Dioxus for the web will be roughly equivalent to the size of a React build (70kb vs 65kb) but it will load significantly faster because WebAssembly can be compiled as it is streamed.

    +

    Examples:

    + +

    TodoMVC example

    +
    +

    Note: Because of the limitations of Wasm, not every crate will work with your web apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).

    +
    +

    Support

    +

    The Web is the best-supported target platform for Dioxus.

    +
      +
    • Because your app will be compiled to WASM you have access to browser APIs through wasm-bingen.
    • +
    • Dioxus provides hydration to resume apps that are rendered on the server. See the fullstack getting started guide for more information.
    • +
    +

    Tooling

    +

    To develop your Dioxus app for the web, you'll need a tool to build and serve your assets. We recommend using dioxus-cli which includes a build system, Wasm optimization, a dev server, and support hot reloading:

    +
    cargo install dioxus-cli
    +
    +

    Make sure the wasm32-unknown-unknown target for rust is installed:

    +
    rustup target add wasm32-unknown-unknown
    +
    +

    Creating a Project

    +

    Create a new crate:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the web renderer as dependencies (this will edit your Cargo.toml):

    +
    cargo add dioxus
    +cargo add dioxus-web
    +
    +

    Edit your main.rs:

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the web app
    +    dioxus_web::launch(App);
    +}
    +
    +// create a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    +

    And to serve our app:

    +
    dioxus serve
    +
    +

    Server-Side Rendering

    +

    For lower-level control over the rendering process, you can use the dioxus-ssr crate directly. This can be useful when integrating with a web framework that dioxus-server does not support, or pre-rendering pages.

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus SSR with Axum.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add Dioxus and the ssr renderer as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-ssr
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "0.4.5"
    +dioxus = { version = "*" }
    +dioxus-ssr = { version = "*" }
    +tokio = { version = "1.15.0", features = ["full"] }
    +
    +

    Now, set up your Axum app to respond on an endpoint.

    +
    #![allow(non_snake_case)]
    +use axum::{response::Html, routing::get, Router};
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +#[tokio::main]
    +async fn main() {
    +    let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
    +    println!("listening on http://{}", addr);
    +
    +    axum::Server::bind(&addr)
    +        .serve(
    +            Router::new()
    +                .route("/", get(app_endpoint))
    +                .into_make_service(),
    +        )
    +        .await
    +        .unwrap();
    +}
    +
    +
    +

    And then add our endpoint. We can either render rsx! directly:

    +
    
    +#![allow(unused)]
    +fn main() {
    +async fn app_endpoint() -> Html<String> {
    +    // render the rsx! macro to HTML
    +    Html(dioxus_ssr::render_lazy(rsx! {
    +        div { "hello world!" }
    +    }))
    +}
    +}
    +
    +

    Or we can render VirtualDoms.

    +
    
    +#![allow(unused)]
    +fn main() {
    +async fn second_app_endpoint() -> Html<String> {
    +    // create a component that renders a div with the text "hello world"
    +    fn app(cx: Scope) -> Element {
    +        cx.render(rsx!(div { "hello world" }))
    +    }
    +    // create a VirtualDom with the app component
    +    let mut app = VirtualDom::new(app);
    +    // rebuild the VirtualDom before rendering
    +    let _ = app.rebuild();
    +
    +    // render the VirtualDom to HTML
    +    Html(dioxus_ssr::render(&app))
    +}
    +}
    +
    +

    And then add our app component:

    +
    
    +#![allow(unused)]
    +fn main() {
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +

    And that's it!

    +

    Multithreaded Support

    +

    The Dioxus VirtualDom, sadly, is not currently Send. Internally, we use quite a bit of interior mutability which is not thread-safe. +When working with web frameworks that require Send, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to spawn a VirtualDom on its own thread and communicate with it via channels or create a pool of VirtualDoms. +You might notice that you cannot hold the VirtualDom across an await point. Because Dioxus is currently not ThreadSafe, it must remain on the thread it started. We are working on loosening this requirement.

    +

    Fullstack

    +

    Liveview

    +

    Liveview allows apps to run on the server and render in the browser. It uses WebSockets to communicate between the server and the browser.

    +

    Examples:

    + +

    Support

    +

    Liveview is currently limited in capability when compared to the Web platform. Liveview apps run on the server in a native thread. This means that browser APIs are not available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs are accessible, so streaming, WebSockets, filesystem, etc are all viable APIs.

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus Liveview with Axum.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd app
    +
    +

    Add Dioxus and the liveview renderer with the Axum feature as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-liveview --features axum
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "0.4.5"
    +dioxus = { version = "*" }
    +dioxus-liveview = { version = "*", features = ["axum"] }
    +tokio = { version = "1.15.0", features = ["full"] }
    +
    +

    Now, set up your Axum app to respond on an endpoint.

    +
    #[tokio::main]
    +async fn main() {
    +    let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();
    +
    +    let view = dioxus_liveview::LiveViewPool::new();
    +
    +    let app = Router::new()
    +        // The root route contains the glue code to connect to the WebSocket
    +        .route(
    +            "/",
    +            get(move || async move {
    +                Html(format!(
    +                    r#"
    +                <!DOCTYPE html>
    +                <html>
    +                <head> <title>Dioxus LiveView with Axum</title>  </head>
    +                <body> <div id="main"></div> </body>
    +                {glue}
    +                </html>
    +                "#,
    +                    // Create the glue code to connect to the WebSocket on the "/ws" route
    +                    glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws"))
    +                ))
    +            }),
    +        )
    +        // The WebSocket route is what Dioxus uses to communicate with the browser
    +        .route(
    +            "/ws",
    +            get(move |ws: WebSocketUpgrade| async move {
    +                ws.on_upgrade(move |socket| async move {
    +                    // When the WebSocket is upgraded, launch the LiveView with the app component
    +                    _ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
    +                })
    +            }),
    +        );
    +
    +    println!("Listening on http://{addr}");
    +
    +    axum::Server::bind(&addr.to_string().parse().unwrap())
    +        .serve(app.into_make_service())
    +        .await
    +        .unwrap();
    +}
    +
    +

    And then add our app component:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn app(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +

    And that's it!

    +

    Terminal UI

    +

    You can build a text-based interface that will run in the terminal using Dioxus.

    +

    Hello World screenshot

    +
    +

    Note: this book was written with HTML-based platforms in mind. You might be able to follow along with TUI, but you'll have to adapt a bit.

    +
    +

    Support

    +

    TUI support is currently quite experimental. But, if you're willing to venture into the realm of the unknown, this guide will get you started.

    +
      +
    • It uses flexbox for the layout
    • +
    • It only supports a subset of the attributes and elements
    • +
    • Regular widgets will not work in the tui render, but the tui renderer has its own widget components that start with a capital letter. See the widgets example
    • +
    • 1px is one character line height. Your regular CSS px does not translate
    • +
    • If your app panics, your terminal is wrecked. This will be fixed eventually
    • +
    +

    Getting Set up

    +

    Start by making a new package and adding Dioxus and the TUI renderer as dependancies.

    +
    cargo new --bin demo
    +cd demo
    +cargo add dioxus
    +cargo add dioxus-tui
    +
    +

    Then, edit your main.rs with the basic template.

    +
    #![allow(non_snake_case)]
    +// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    // launch the app in the terminal
    +    dioxus_tui::launch(App);
    +}
    +
    +// create a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +
    +

    To run our app:

    +
    cargo run
    +
    +

    Press "ctrl-c" to close the app. To switch from "ctrl-c" to just "q" to quit you can launch the app with a configuration to disable the default quit and use the root TuiContext to quit on your own.

    +
    // todo remove deprecated
    +#![allow(non_snake_case, deprecated)]
    +
    +use dioxus::events::{KeyCode, KeyboardEvent};
    +use dioxus::prelude::*;
    +use dioxus_tui::TuiContext;
    +
    +fn main() {
    +    dioxus_tui::launch_cfg(
    +        App,
    +        dioxus_tui::Config::new()
    +            .without_ctrl_c_quit()
    +            // Some older terminals only support 16 colors or ANSI colors
    +            // If your terminal is one of these, change this to BaseColors or ANSI
    +            .with_rendering_mode(dioxus_tui::RenderingMode::Rgb),
    +    );
    +}
    +
    +fn App(cx: Scope) -> Element {
    +    let tui_ctx: TuiContext = cx.consume_context().unwrap();
    +
    +    cx.render(rsx! {
    +        div {
    +            width: "100%",
    +            height: "10px",
    +            background_color: "red",
    +            justify_content: "center",
    +            align_items: "center",
    +            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.key_code {
    +                tui_ctx.quit();
    +            },
    +
    +            "Hello world!"
    +        }
    +    })
    +}
    +
    +

    Mobile App

    +

    Build a mobile app with Dioxus!

    +

    Example: Todo App

    +

    Support

    +

    Mobile is currently the least-supported renderer target for Dioxus. Mobile apps are rendered with either the platform's WebView or experimentally through WGPU. WebView doesn't support animations, transparency, and native widgets.

    +

    Mobile support is currently best suited for CRUD-style apps, ideally for internal teams who need to develop quickly but don't care much about animations or native widgets.

    +

    This guide is primarily targeted at iOS apps, however, you can follow it while using the android guide in cargo-mobile.

    +

    Getting Set up

    +

    Getting set up with mobile can be quite challenging. The tooling here isn't great (yet) and might take some hacking around to get things working. macOS M1 is broadly unexplored and might not work for you.

    +

    We're going to be using cargo-mobile to build for mobile. First, install it:

    +
    cargo install --git https://github.com/BrainiumLLC/cargo-mobile
    +
    +

    And then initialize your app for the right platform. Use the winit template for now. Right now, there's no "Dioxus" template in cargo-mobile.

    +
    cargo mobile init
    +
    +

    We're going to completely clear out the dependencies it generates for us, swapping out winit with dioxus-mobile.

    +
    
    +[package]
    +name = "dioxus-ios-demo"
    +version = "0.1.0"
    +authors = []
    +edition = "2018"
    +
    +
    +# leave the `lib` declaration
    +[lib]
    +crate-type = ["staticlib", "cdylib", "rlib"]
    +
    +
    +# leave the binary it generates for us
    +[[bin]]
    +name = "dioxus-ios-demo-desktop"
    +path = "gen/bin/desktop.rs"
    +
    +# clear all the dependencies
    +[dependencies]
    +mobile-entry-point = "0.1.0"
    +dioxus = { version = "*"}
    +dioxus-desktop = { version = "*" }
    +simple_logger = "*"
    +
    +

    Edit your lib.rs:

    +
    use dioxus::prelude::*;
    +
    +fn main() {
    +    dioxus_desktop::launch(app);
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    cx.render(rsx!{
    +        div {
    +            "hello world!"
    +        }
    +    })
    +}
    +
    +

    Setting Up Hot Reload

    +
      +
    1. Hot reloading allows much faster iteration times inside of rsx calls by interpreting them and streaming the edits.
    2. +
    3. It is useful when changing the styling/layout of a program, but will not help with changing the logic of a program.
    4. +
    5. Currently the cli only implements hot reloading for the web renderer. For TUI, desktop, and LiveView you can use the hot reload macro instead.
    6. +
    +

    Web

    +

    For the web renderer, you can use the dioxus cli to serve your application with hot reloading enabled.

    +

    Setup

    +

    Install dioxus-cli. +Hot reloading is automatically enabled when using the web renderer on debug builds.

    +

    Usage

    +
      +
    1. Run:
    2. +
    +
    dioxus serve --hot-reload
    +
    +
      +
    1. Change some code within a rsx or render macro
    2. +
    3. Open your localhost in a browser
    4. +
    5. Save and watch the style change without recompiling
    6. +
    +

    Desktop/Liveview/TUI/Server

    +

    For desktop, LiveView, and tui, you can place the hot reload macro at the top of your main function to enable hot reloading. +Hot reloading is automatically enabled on debug builds.

    +

    For more information about hot reloading on native platforms and configuration options see the dioxus-hot-reload crate.

    +

    Setup

    +

    Add the following to your main function:

    +
    fn main() {
    +    hot_reload_init!();
    +    // launch your application
    +}
    +
    +

    Usage

    +
      +
    1. Run:
    2. +
    +
    cargo run
    +
    +
      +
    1. Change some code within a rsx or render macro
    2. +
    3. Save and watch the style change without recompiling
    4. +
    +

    Limitations

    +
      +
    1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
    2. +
    3. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.
    4. +
    +

    Describing the UI

    +

    Dioxus is a declarative framework. This means that instead of telling Dioxus what to do (e.g. to "create an element" or "set the color to red") we simply declare what we want the UI to look like using RSX.

    +

    You have already seen a simple example of RSX syntax in the "hello world" application:

    +
    
    +#![allow(unused)]
    +fn main() {
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +

    Here, we use the rsx! macro to declare that we want a div element, containing the text "Hello, world!". Dioxus takes the RSX and constructs a UI from it.

    +

    RSX Features

    +

    RSX is very similar to HTML in that it describes elements with attributes and children. Here's an empty div element in RSX, as well as the resulting HTML:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!(div {
    +    // attributes / listeners
    +    // children
    +}))
    +}
    +
    +
    <div></div>
    +
    +

    Attributes

    +

    Attributes (and listeners) modify the behavior or appearance of the element they are attached to. They are specified inside the {} brackets, using the name: value syntax. You can provide the value as a literal in the RSX:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!(a {
    +    href: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    +    class: "primary_button",
    +    color: "red",
    +}))
    +}
    +
    +
    <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" class="primary_button" autofocus="true" style="color: red"></a>
    +
    +
    +

    Note: All attributes defined in dioxus-html follow the snake_case naming convention. They transform their snake_case names to HTML's camelCase attributes.

    +
    +
    +

    Note: Styles can be used directly outside of the style: attribute. In the above example, color: "red" is turned into style="color: red".

    +
    +

    Custom Attributes

    +

    Dioxus has a pre-configured set of attributes that you can use. RSX is validated at compile time to make sure you didn't specify an invalid attribute. If you want to override this behavior with a custom attribute name, specify the attribute in quotes:

    +
    
    +#![allow(unused)]
    +fn main() {
    +    cx.render(rsx!(b {
    +        "customAttribute": "value",
    +    }))
    +}
    +
    +
    <b customAttribute="value">
    +</b>
    +
    +

    Interpolation

    +

    Similarly to how you can format Rust strings, you can also interpolate in RSX text. Use {variable} to Display the value of a variable in a string, or {variable:?} to use the Debug representation:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let coordinates = (42, 0);
    +let country = "es";
    +cx.render(rsx!(div {
    +    class: "country-{country}",
    +    "position": "{coordinates:?}",
    +    // arbitrary expressions are allowed,
    +    // as long as they don't contain `{}`
    +    div {
    +        "{country.to_uppercase()}"
    +    },
    +    div {
    +        "{7*6}"
    +    },
    +    // {} can be escaped with {{}}
    +    div {
    +        "{{}}"
    +    },
    +}))
    +}
    +
    +
    <div class="country-es" position="(42, 0)">
    +    <div>ES</div>
    +    <div>42</div>
    +    <div>{}</div>
    +</div>
    +
    +

    Children

    +

    To add children to an element, put them inside the {} brackets after all attributes and listeners in the element. They can be other elements, text, or components. For example, you could have an ol (ordered list) element, containing 3 li (list item) elements, each of which contains some text:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!(ol {
    +    li {"First Item"}
    +    li {"Second Item"}
    +    li {"Third Item"}
    +}))
    +}
    +
    +
    <ol>
    +    <li>First Item</li>
    +    <li>Second Item</li>
    +    <li>Third Item</li>
    +</ol>
    +
    +

    Fragments

    +

    You can render multiple elements at the top level of rsx! and they will be automatically grouped.

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!(
    +    p {"First Item"},
    +    p {"Second Item"},
    +))
    +}
    +
    +
    <p>First Item</p>
    +<p>Second Item</p>
    +
    +

    Expressions

    +

    You can include arbitrary Rust expressions as children within RSX that implements IntoDynNode. This is useful for displaying data from an iterator:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let text = "Dioxus";
    +cx.render(rsx!(span {
    +    text.to_uppercase(),
    +    // create a list of text from 0 to 9
    +    (0..10).map(|i| rsx!{ i.to_string() })
    +}))
    +}
    +
    +
    <span>DIOXUS0123456789</span>
    +
    +

    Loops

    +

    In addition to iterators you can also use for loops directly within RSX:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!{
    +    // use a for loop where the body itself is RSX
    +    div {
    +        // create a list of text from 0 to 9
    +        for i in 0..3 {
    +            // NOTE: the body of the loop is RSX not a rust statement
    +            div {
    +                "{i}"
    +            }
    +        }
    +    }
    +    // iterator equivalent
    +    div {
    +        (0..3).map(|i| rsx!{ div { "{i}" } })
    +    }
    +})
    +}
    +
    +
    <div>0</div>
    +<div>1</div>
    +<div>2</div>
    +<div>0</div>
    +<div>1</div>
    +<div>2</div>
    +
    +

    If statements

    +

    You can also use if statements without an else branch within RSX:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!{
    +    // use if statements without an else
    +    if true {
    +        rsx!(div { "true" })
    +    }
    +})
    +}
    +
    +
    <div>true</div>
    +
    +

    Special Attributes

    +

    While most attributes are simply passed on to the HTML, some have special behaviors.

    +

    The HTML Escape Hatch

    +

    If you're working with pre-rendered assets, output from templates, or output from a JS library, then you might want to pass HTML directly instead of going through Dioxus. In these instances, reach for dangerous_inner_html.

    +

    For example, shipping a markdown-to-Dioxus converter might significantly bloat your final application size. Instead, you'll want to pre-render your markdown to HTML and then include the HTML directly in your output. We use this approach for the Dioxus homepage:

    +
    
    +#![allow(unused)]
    +fn main() {
    +// this should come from a trusted source
    +let contents = "live <b>dangerously</b>";
    +
    +cx.render(rsx! {
    +    div {
    +        dangerous_inner_html: "{contents}",
    +    }
    +})
    +}
    +
    +
    +

    Note! This attribute is called "dangerous_inner_html" because it is dangerous to pass it data you don't trust. If you're not careful, you can easily expose cross-site scripting (XSS) attacks to your users.

    +

    If you're handling untrusted input, make sure to sanitize your HTML before passing it into dangerous_inner_html – or just pass it to a Text Element to escape any HTML tags.

    +
    +

    Boolean Attributes

    +

    Most attributes, when rendered, will be rendered exactly as the input you provided. However, some attributes are considered "boolean" attributes and just their presence determines whether they affect the output. For these attributes, a provided value of "false" will cause them to be removed from the target element.

    +

    So this RSX wouldn't actually render the hidden attribute:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    div {
    +        hidden: "false",
    +        "hello"
    +    }
    +})
    +}
    +
    +
    <div>hello</div>
    +
    +

    Not all attributes work like this however. Only the following attributes have this behavior:

    +
      +
    • allowfullscreen
    • +
    • allowpaymentrequest
    • +
    • async
    • +
    • autofocus
    • +
    • autoplay
    • +
    • checked
    • +
    • controls
    • +
    • default
    • +
    • defer
    • +
    • disabled
    • +
    • formnovalidate
    • +
    • hidden
    • +
    • ismap
    • +
    • itemscope
    • +
    • loop
    • +
    • multiple
    • +
    • muted
    • +
    • nomodule
    • +
    • novalidate
    • +
    • open
    • +
    • playsinline
    • +
    • readonly
    • +
    • required
    • +
    • reversed
    • +
    • selected
    • +
    • truespeed
    • +
    +

    For any other attributes, a value of "false" will be sent directly to the DOM.

    +

    Components

    +

    Just like you wouldn't want to write a complex program in a single, long, main function, you shouldn't build a complex UI in a single App function. Instead, you should break down the functionality of an app in logical parts called components.

    +

    A component is a Rust function, named in UpperCammelCase, that takes a Scope parameter and returns an Element describing the UI it wants to render. In fact, our App function is a component!

    +
    
    +#![allow(unused)]
    +fn main() {
    +// define a component that renders a div with the text "Hello, world!"
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "Hello, world!"
    +        }
    +    })
    +}
    +}
    +
    +
    +

    You'll probably want to add #![allow(non_snake_case)] to the top of your crate to avoid warnings about UpperCammelCase component names

    +
    +

    A Component is responsible for some rendering task – typically, rendering an isolated part of the user interface. For example, you could have an About component that renders a short description of Dioxus Labs:

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub fn About(cx: Scope) -> Element {
    +    cx.render(rsx!(p {
    +        b {"Dioxus Labs"}
    +        " An Open Source project dedicated to making Rust UI wonderful."
    +    }))
    +}
    +}
    +
    +

    Then, you can render your component in another component, similarly to how elements are rendered:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        About {},
    +        About {},
    +    })
    +}
    +}
    +
    +

    Screenshot containing the About component twice

    +
    +

    At this point, it might seem like components are nothing more than functions. However, as you learn more about the features of Dioxus, you'll see that they are actually more powerful!

    +
    +

    Component Props

    +

    Just like you can pass arguments to a function, you can pass props to a component that customize its behavior! The components we've seen so far didn't accept any props – so let's write some components that do.

    +

    #[derive(Props)]

    +

    Component props are a single struct annotated with #[derive(Props)]. For a component to accept props, the type of its argument must be Scope<YourPropsStruct>. Then, you can access the value of the props using cx.props.

    +

    There are 2 flavors of Props structs:

    +
      +
    • Owned props: +
        +
      • Don't have an associated lifetime
      • +
      • Implement PartialEq, allow for memoization (if the props don't change, Dioxus won't re-render the component)
      • +
      +
    • +
    • Borrowed props: +
        +
      • Borrow from a parent component
      • +
      • Cannot be memoized due to lifetime constraints
      • +
      +
    • +
    +

    Owned Props

    +

    Owned Props are very simple – they don't borrow anything. Example:

    +
    
    +#![allow(unused)]
    +fn main() {
    +// Remember: Owned props must implement `PartialEq`!
    +#[derive(PartialEq, Props)]
    +struct LikesProps {
    +    score: i32,
    +}
    +
    +fn Likes(cx: Scope<LikesProps>) -> Element {
    +    cx.render(rsx! {
    +        div {
    +            "This post has ",
    +            b { "{cx.props.score}" },
    +            " likes"
    +        }
    +    })
    +}
    +}
    +
    +

    You can then pass prop values to the component the same way you would pass attributes to an element:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        Likes {
    +            score: 42,
    +        },
    +    })
    +}
    +}
    +
    +

    Screenshot: Likes component

    +

    Borrowed Props

    +

    Owned props work well if your props are easy to copy around – like a single number. But what if we need to pass a larger data type, like a String from an App Component to a TitleCard subcomponent? A naive solution might be to .clone() the String, creating a copy of it for the subcomponent – but this would be inefficient, especially for larger Strings.

    +

    Rust allows for something more efficient – borrowing the String as a &str – this is what Borrowed Props are for!

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +struct TitleCardProps<'a> {
    +    title: &'a str,
    +}
    +
    +fn TitleCard<'a>(cx: Scope<'a, TitleCardProps<'a>>) -> Element {
    +    cx.render(rsx! {
    +        h1 { "{cx.props.title}" }
    +    })
    +}
    +}
    +
    +

    We can then use the component like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let hello = "Hello Dioxus!";
    +
    +    cx.render(rsx!(TitleCard { title: hello }))
    +}
    +}
    +
    +

    Screenshot: TitleCard component

    +

    Borrowed props can be very useful, but they do not allow for memorization so they will always rerun when the parent scope is rerendered. Because of this Borrowed Props should be reserved for components that are cheap to rerun or places where cloning data is an issue. Using Borrowed Props everywhere will result in large parts of your app rerunning every interaction.

    +

    Prop Options

    +

    The #[derive(Props)] macro has some features that let you customize the behavior of props.

    +

    Optional Props

    +

    You can create optional fields by using the Option<…> type for a field:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +struct OptionalProps<'a> {
    +    title: &'a str,
    +    subtitle: Option<&'a str>,
    +}
    +
    +fn Title<'a>(cx: Scope<'a, OptionalProps>) -> Element<'a> {
    +    cx.render(rsx!(h1{
    +        "{cx.props.title}: ",
    +        cx.props.subtitle.unwrap_or("No subtitle provided"),
    +    }))
    +}
    +}
    +
    +

    Then, you can choose to either provide them or not:

    +
    
    +#![allow(unused)]
    +fn main() {
    +Title {
    +    title: "Some Title",
    +},
    +Title {
    +    title: "Some Title",
    +    subtitle: "Some Subtitle",
    +},
    +// Providing an Option explicitly won't compile though:
    +// Title {
    +//     title: "Some Title",
    +//     subtitle: None,
    +// },
    +}
    +
    +

    Explicitly Required Options

    +

    If you want to explicitly require an Option, and not an optional prop, you can annotate it with #[props(!optional)]:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +struct ExplicitOptionProps<'a> {
    +    title: &'a str,
    +    #[props(!optional)]
    +    subtitle: Option<&'a str>,
    +}
    +
    +fn ExplicitOption<'a>(cx: Scope<'a, ExplicitOptionProps>) -> Element<'a> {
    +    cx.render(rsx!(h1 {
    +        "{cx.props.title}: ",
    +        cx.props.subtitle.unwrap_or("No subtitle provided"),
    +    }))
    +}
    +}
    +
    +

    Then, you have to explicitly pass either Some("str") or None:

    +
    
    +#![allow(unused)]
    +fn main() {
    +ExplicitOption {
    +    title: "Some Title",
    +    subtitle: None,
    +},
    +ExplicitOption {
    +    title: "Some Title",
    +    subtitle: Some("Some Title"),
    +},
    +// This won't compile:
    +// ExplicitOption {
    +//     title: "Some Title",
    +// },
    +}
    +
    +

    Default Props

    +

    You can use #[props(default = 42)] to make a field optional and specify its default value:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(PartialEq, Props)]
    +struct DefaultProps {
    +    // default to 42 when not provided
    +    #[props(default = 42)]
    +    number: i64,
    +}
    +
    +fn DefaultComponent(cx: Scope<DefaultProps>) -> Element {
    +    cx.render(rsx!(h1 { "{cx.props.number}" }))
    +}
    +}
    +
    +

    Then, similarly to optional props, you don't have to provide it:

    +
    
    +#![allow(unused)]
    +fn main() {
    +DefaultComponent {
    +    number: 5,
    +},
    +DefaultComponent {},
    +}
    +
    +

    Automatic Conversion with .into

    +

    It is common for Rust functions to accept impl Into<SomeType> rather than just SomeType to support a wider range of parameters. If you want similar functionality with props, you can use #[props(into)]. For example, you could add it on a String prop – and &str will also be automatically accepted, as it can be converted into String:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(PartialEq, Props)]
    +struct IntoProps {
    +    #[props(into)]
    +    string: String,
    +}
    +
    +fn IntoComponent(cx: Scope<IntoProps>) -> Element {
    +    cx.render(rsx!(h1 { "{cx.props.string}" }))
    +}
    +}
    +
    +

    Then, you can use it so:

    +
    
    +#![allow(unused)]
    +fn main() {
    +IntoComponent {
    +    string: "some &str",
    +},
    +}
    +
    +

    The inline_props macro

    +

    So far, every Component function we've seen had a corresponding ComponentProps struct to pass in props. This was quite verbose... Wouldn't it be nice to have props as simple function arguments? Then we wouldn't need to define a Props struct, and instead of typing cx.props.whatever, we could just use whatever directly!

    +

    inline_props allows you to do just that. Instead of typing the "full" version:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props, PartialEq)]
    +struct TitleCardProps {
    +    title: String,
    +}
    +
    +fn TitleCard(cx: Scope<TitleCardProps>) -> Element {
    +    cx.render(rsx!{
    +        h1 { "{cx.props.title}" }
    +    })
    +}
    +}
    +
    +

    ...you can define a function that accepts props as arguments. Then, just annotate it with #[inline_props], and the macro will turn it into a regular Component for you:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[inline_props]
    +fn TitleCard(cx: Scope, title: String) -> Element {
    +    cx.render(rsx!{
    +        h1 { "{title}" }
    +    })
    +}
    +}
    +
    +
    +

    While the new Component is shorter and easier to read, this macro should not be used by library authors since you have less control over Prop documentation.

    +
    +

    Component Children

    +

    In some cases, you may wish to create a component that acts as a container for some other content, without the component needing to know what that content is. To achieve this, create a prop of type Element:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +struct ClickableProps<'a> {
    +    href: &'a str,
    +    body: Element<'a>,
    +}
    +
    +fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
    +    cx.render(rsx!(
    +        a {
    +            href: "{cx.props.href}",
    +            class: "fancy-button",
    +            &cx.props.body
    +        }
    +    ))
    +}
    +}
    +
    +

    Then, when rendering the component, you can pass in the output of cx.render(rsx!(...)):

    +
    
    +#![allow(unused)]
    +fn main() {
    +    cx.render(rsx! {
    +        Clickable {
    +            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
    +            body: cx.render(rsx!("How to " i {"not"} " be seen")),
    +        }
    +    })
    +}
    +
    +
    +

    Note: Since Element<'a> is a borrowed prop, there will be no memoization.

    +
    +
    +

    Warning: While it may compile, do not include the same Element more than once in the RSX. The resulting behavior is unspecified.

    +
    +

    The children field

    +

    Rather than passing the RSX through a regular prop, you may wish to accept children similarly to how elements can have children. The "magic" children prop lets you achieve this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +struct ClickableProps<'a> {
    +    href: &'a str,
    +    children: Element<'a>,
    +}
    +
    +fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
    +    cx.render(rsx!(
    +        a {
    +            href: "{cx.props.href}",
    +            class: "fancy-button",
    +            &cx.props.children
    +        }
    +    ))
    +}
    +}
    +
    +

    This makes using the component much simpler: simply put the RSX inside the {} brackets – and there is no need for a render call or another macro!

    +
    
    +#![allow(unused)]
    +fn main() {
    +    cx.render(rsx! {
    +        Clickable {
    +            href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
    +            "How to " i {"not"} " be seen"
    +        }
    +    })
    +}
    +
    +

    Interactivity

    +

    So far, we've learned how to describe the structure and properties of our user interfaces. However, most interfaces need to be interactive in order to be useful. In this chapter, we describe how to make a Dioxus app that responds to the user.

    +

    Event Handlers

    +

    Event handlers are used to respond to user actions. For example, an event handler could be triggered when the user clicks, scrolls, moves the mouse, or types a character.

    +

    Event handlers are attached to elements. For example, we usually don't care about all the clicks that happen within an app, only those on a particular button.

    +

    Event handlers are similar to regular attributes, but their name usually starts with on- and they accept closures as values. The closure will be called whenever the event it listens for is triggered and will be passed that event.

    +

    For example, to handle clicks on an element, we can specify an onclick handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    button {
    +        onclick: move |event| println!("Clicked! Event: {event:?}"),
    +        "click me!"
    +    }
    +})
    +}
    +
    +

    The Event object

    +

    Event handlers receive an Event object containing information about the event. Different types of events contain different types of data. For example, mouse-related events contain MouseData, which tells you things like where the mouse was clicked and what mouse buttons were used.

    +

    In the example above, this event data was logged to the terminal:

    +
    Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }
    +Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }
    +
    +

    To learn what the different event types for HTML provide, read the events module docs.

    +

    Event propagation

    +

    Some events will trigger first on the element the event originated at upward. For example, a click event on a button inside a div would first trigger the button's event listener and then the div's event listener.

    +
    +

    For more information about event propigation see the mdn docs on event bubling

    +
    +

    If you want to prevent this behavior, you can call stop_propagation() on the event:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    div {
    +        onclick: move |_event| {},
    +        "outer",
    +        button {
    +            onclick: move |event| {
    +                // now, outer won't be triggered
    +                event.stop_propagation();
    +            },
    +            "inner"
    +        }
    +    }
    +})
    +}
    +
    +

    Prevent Default

    +

    Some events have a default behavior. For keyboard events, this might be entering the typed character. For mouse events, this might be selecting some text.

    +

    In some instances, might want to avoid this default behavior. For this, you can add the prevent_default attribute with the name of the handler whose default behavior you want to stop. This attribute can be used for multiple handlers using their name separated by spaces:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    input {
    +        prevent_default: "oninput onclick",
    +    }
    +})
    +}
    +
    +

    Any event handlers will still be called.

    +
    +

    Normally, in React or JavaScript, you'd call "preventDefault" on the event in the callback. Dioxus does not currently support this behavior. Note: this means you cannot conditionally prevent default behavior based on the data in the event.

    +
    +

    Handler Props

    +

    Sometimes, you might want to make a component that accepts an event handler. A simple example would be a FancyButton component, which accepts an on_click handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[derive(Props)]
    +pub struct FancyButtonProps<'a> {
    +    on_click: EventHandler<'a, MouseEvent>,
    +}
    +
    +pub fn FancyButton<'a>(cx: Scope<'a, FancyButtonProps<'a>>) -> Element<'a> {
    +    cx.render(rsx!(button {
    +        class: "fancy-button",
    +        onclick: move |evt| cx.props.on_click.call(evt),
    +        "click me pls."
    +    }))
    +}
    +}
    +
    +

    Then, you can use it like any other handler:

    +
    
    +#![allow(unused)]
    +fn main() {
    +    cx.render(rsx! {
    +        FancyButton {
    +            on_click: move |event| println!("Clicked! {event:?}")
    +        }
    +    })
    +}
    +
    +
    +

    Note: just like any other attribute, you can name the handlers anything you want! Though they must start with on, for the prop to be automatically turned into an EventHandler at the call site.

    +

    You can also put custom data in the event, rather than e.g. MouseData

    +
    +

    Hooks and Component State

    +

    So far our components have had no state like a normal rust functions. However, in a UI component, it is often useful to have stateful functionality to build user interactions. For example, you might want to track whether the user has opened a drop-down, and render different things accordingly.

    +

    Hooks allow us to create state in our components. Hooks are Rust functions that take a reference to ScopeState (in a component, you can pass cx), and provide you with functionality and state.

    +

    use_state Hook

    +

    use_state is one of the simplest hooks.

    +
      +
    • You provide a closure that determines the initial value
    • +
    • use_state gives you the current value, and a way to update it by setting it to something else
    • +
    • When the value updates, use_state makes the component re-render, and provides you with the new value
    • +
    +

    For example, you might have seen the counter example, in which state (a number) is tracked using the use_state hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    // count will be initialized to 0 the first time the component is rendered
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "High-Five counter: {count}" }
    +        button {
    +            onclick: move |_| {
    +                // changing the count will cause the component to re-render
    +                count += 1
    +            },
    +            "Up high!"
    +        }
    +        button {
    +            onclick: move |_| {
    +                // changing the count will cause the component to re-render
    +                count -= 1
    +            },
    +            "Down low!"
    +        }
    +    ))
    +}
    +}
    +
    +

    Screenshot: counter app

    +

    Every time the component's state changes, it re-renders, and the component function is called, so you can describe what you want the new UI to look like. You don't have to worry about "changing" anything – just describe what you want in terms of the state, and Dioxus will take care of the rest!

    +
    +

    use_state returns your value wrapped in a smart pointer of type UseState. This is why you can both read the value and update it, even within an event handler.

    +
    +

    You can use multiple hooks in the same component if you want:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let mut count_a = use_state(cx, || 0);
    +    let mut count_b = use_state(cx, || 0);
    +
    +    cx.render(rsx!(
    +        h1 { "Counter_a: {count_a}" }
    +        button { onclick: move |_| count_a += 1, "a++" }
    +        button { onclick: move |_| count_a -= 1, "a--" }
    +        h1 { "Counter_b: {count_b}" }
    +        button { onclick: move |_| count_b += 1, "b++" }
    +        button { onclick: move |_| count_b -= 1, "b--" }
    +    ))
    +}
    +}
    +
    +

    Screenshot: app with two counters

    +

    Rules of Hooks

    +

    The above example might seem a bit magic, since Rust functions are typically not associated with state. Dioxus allows hooks to maintain state across renders through a reference to ScopeState, which is why you must pass &cx to them.

    +

    But how can Dioxus differentiate between multiple hooks in the same component? As you saw in the second example, both use_state functions were called with the same parameters, so how come they can return different things when the counters are different?

    +
    
    +#![allow(unused)]
    +fn main() {
    +    let mut count_a = use_state(cx, || 0);
    +    let mut count_b = use_state(cx, || 0);
    +}
    +
    +

    This is only possible because the two hooks are always called in the same order, so Dioxus knows which is which. Because the order you call hooks matters, you must follow certain rules when using hooks:

    +
      +
    1. Hooks may be only used in components or other hooks (we'll get to that later)
    2. +
    3. On every call to the component function +
        +
      1. The same hooks must be called (except in the case of early returns, as explained later in the Error Handling chapter)
      2. +
      3. In the same order
      4. +
      +
    4. +
    5. Hooks name's should start with use_ so you don't accidentally confuse them with regular functions
    6. +
    +

    These rules mean that there are certain things you can't do with hooks:

    +

    No Hooks in Conditionals

    +
    
    +#![allow(unused)]
    +fn main() {
    +// ❌ don't call hooks in conditionals!
    +// We must ensure that the same hooks will be called every time
    +// But `if` statements only run if the conditional is true!
    +// So we might violate rule 2.
    +if you_are_happy && you_know_it {
    +    let something = use_state(cx, || "hands");
    +    println!("clap your {something}")
    +}
    +
    +// ✅ instead, *always* call use_state
    +// You can put other stuff in the conditional though
    +let something = use_state(cx, || "hands");
    +if you_are_happy && you_know_it {
    +    println!("clap your {something}")
    +}
    +}
    +
    +

    No Hooks in Closures

    +
    
    +#![allow(unused)]
    +fn main() {
    +// ❌ don't call hooks inside closures!
    +// We can't guarantee that the closure, if used, will be called in the same order every time
    +let _a = || {
    +    let b = use_state(cx, || 0);
    +    b.get()
    +};
    +
    +// ✅ instead, move hook `b` outside
    +let b = use_state(cx, || 0);
    +let _a = || b.get();
    +}
    +
    +

    No Hooks in Loops

    +
    
    +#![allow(unused)]
    +fn main() {
    +// `names` is a Vec<&str>
    +
    +// ❌ Do not use hooks in loops!
    +// In this case, if the length of the Vec changes, we break rule 2
    +for _name in &names {
    +    let is_selected = use_state(cx, || false);
    +    println!("selected: {is_selected}");
    +}
    +
    +// ✅ Instead, use a hashmap with use_ref
    +let selection_map = use_ref(cx, HashMap::<&str, bool>::new);
    +
    +for name in &names {
    +    let is_selected = selection_map.read()[name];
    +    println!("selected: {is_selected}");
    +}
    +}
    +
    +

    use_ref Hook

    +

    use_state is great for tracking simple values. However, you may notice in the UseState API that the only way to modify its value is to replace it with something else (e.g., by calling set, or through one of the +=, -= operators). This works well when it is cheap to construct a value (such as any primitive). But what if you want to maintain more complex data in the components state?

    +

    For example, suppose we want to maintain a Vec of values. If we stored it with use_state, the only way to add a new value to the list would be to create a new Vec with the additional value, and put it in the state. This is expensive! We want to modify the existing Vec instead.

    +

    Thankfully, there is another hook for that, use_ref! It is similar to use_state, but it lets you get a mutable reference to the contained data.

    +

    Here's a simple example that keeps a list of events in a use_ref. We can acquire write access to the state with .with_mut(), and then just .push a new value to the state:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let list = use_ref(cx, Vec::new);
    +
    +    cx.render(rsx!(
    +        p { "Current list: {list.read():?}" }
    +        button {
    +            onclick: move |event| {
    +                list.with_mut(|list| list.push(event));
    +            },
    +            "Click me!"
    +        }
    +    ))
    +}
    +}
    +
    +
    +

    The return values of use_state and use_ref (UseState and UseRef, respectively) are in some ways similar to Cell and RefCell – they provide interior mutability. However, these Dioxus wrappers also ensure that the component gets re-rendered whenever you change the state.

    +
    +

    User Input

    +

    Interfaces often need to provide a way to input data: e.g. text, numbers, checkboxes, etc. In Dioxus, there are two ways you can work with user input.

    +

    Controlled Inputs

    +

    With controlled inputs, you are directly in charge of the state of the input. This gives you a lot of flexibility, and makes it easy to keep things in sync. For example, this is how you would create a controlled text input:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    let name = use_state(cx, || "bob".to_string());
    +
    +    cx.render(rsx! {
    +        input {
    +            // we tell the component what to render
    +            value: "{name}",
    +            // and what to do when the value changes
    +            oninput: move |evt| name.set(evt.value.clone()),
    +        }
    +    })
    +}
    +}
    +
    +

    Notice the flexibility – you can:

    +
      +
    • Also display the same contents in another element, and they will be in sync
    • +
    • Transform the input every time it is modified (e.g. to make sure it is upper case)
    • +
    • Validate the input every time it changes
    • +
    • Have custom logic happening when the input changes (e.g. network request for autocompletion)
    • +
    • Programmatically change the value (e.g. a "randomize" button that fills the input with nonsense)
    • +
    +

    Uncontrolled Inputs

    +

    As an alternative to controlled inputs, you can simply let the platform keep track of the input values. If we don't tell a HTML input what content it should have, it will be editable anyway (this is built into the browser). This approach can be more performant, but less flexible. For example, it's harder to keep the input in sync with another element.

    +

    Since you don't necessarily have the current value of the uncontrolled input in state, you can access it either by listening to oninput events (similarly to controlled components), or, if the input is part of a form, you can access the form data in the form events (e.g. oninput or onsubmit):

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    cx.render(rsx! {
    +        form {
    +            onsubmit: move |event| {
    +                println!("Submitted! {event:?}")
    +            },
    +            input { name: "name", },
    +            input { name: "age", },
    +            input { name: "date", },
    +            input { r#type: "submit", },
    +        }
    +    })
    +}
    +}
    +
    +
    Submitted! UiEvent { data: FormData { value: "", values: {"age": "very old", "date": "1966", "name": "Fred"} } }
    +
    +

    Sharing State

    +

    Often, multiple components need to access the same state. Depending on your needs, there are several ways to implement this.

    +

    Lifting State

    +

    One approach to share state between components is to "lift" it up to the nearest common ancestor. This means putting the use_state hook in a parent component, and passing the needed values down as props.

    +

    Suppose we want to build a meme editor. We want to have an input to edit the meme caption, but also a preview of the meme with the caption. Logically, the meme and the input are 2 separate components, but they need access to the same state (the current caption).

    +
    +

    Of course, in this simple example, we could write everything in one component – but it is better to split everything out in smaller components to make the code more reusable, maintainable, and performant (this is even more important for larger, complex apps).

    +
    +

    We start with a Meme component, responsible for rendering a meme with a given caption:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[inline_props]
    +fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
    +    let container_style = r#"
    +        position: relative;
    +        width: fit-content;
    +    "#;
    +
    +    let caption_container_style = r#"
    +        position: absolute;
    +        bottom: 0;
    +        left: 0;
    +        right: 0;
    +        padding: 16px 8px;
    +    "#;
    +
    +    let caption_style = r"
    +        font-size: 32px;
    +        margin: 0;
    +        color: white;
    +        text-align: center;
    +    ";
    +
    +    cx.render(rsx!(
    +        div {
    +            style: "{container_style}",
    +            img {
    +                src: "https://i.imgflip.com/2zh47r.jpg",
    +                height: "500px",
    +            },
    +            div {
    +                style: "{caption_container_style}",
    +                p {
    +                    style: "{caption_style}",
    +                    "{caption}"
    +                }
    +            }
    +        }
    +    ))
    +}
    +}
    +
    +
    +

    Note that the Meme component is unaware where the caption is coming from – it could be stored in use_state, use_ref, or a constant. This ensures that it is very reusable – the same component can be used for a meme gallery without any changes!

    +
    +

    We also create a caption editor, completely decoupled from the meme. The caption editor must not store the caption itself – otherwise, how will we provide it to the Meme component? Instead, it should accept the current caption as a prop, as well as an event handler to delegate input events to:

    +
    
    +#![allow(unused)]
    +fn main() {
    +#[inline_props]
    +fn CaptionEditor<'a>(
    +    cx: Scope<'a>,
    +    caption: &'a str,
    +    on_input: EventHandler<'a, FormEvent>,
    +) -> Element<'a> {
    +    let input_style = r"
    +        border: none;
    +        background: cornflowerblue;
    +        padding: 8px 16px;
    +        margin: 0;
    +        border-radius: 4px;
    +        color: white;
    +    ";
    +
    +    cx.render(rsx!(input {
    +        style: "{input_style}",
    +        value: "{caption}",
    +        oninput: move |event| on_input.call(event),
    +    }))
    +}
    +}
    +
    +

    Finally, a third component will render the other two as children. It will be responsible for keeping the state and passing down the relevant props.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn MemeEditor(cx: Scope) -> Element {
    +    let container_style = r"
    +        display: flex;
    +        flex-direction: column;
    +        gap: 16px;
    +        margin: 0 auto;
    +        width: fit-content;
    +    ";
    +
    +    let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
    +
    +    cx.render(rsx! {
    +        div {
    +            style: "{container_style}",
    +            h1 { "Meme Editor" },
    +            Meme {
    +                caption: caption,
    +            },
    +            CaptionEditor {
    +                caption: caption,
    +                on_input: move |event: FormEvent| {caption.set(event.value.clone());},
    +            },
    +        }
    +    })
    +}
    +}
    +
    +

    Meme Editor Screenshot: An old plastic skeleton sitting on a park bench. Caption: "me waiting for a language feature"

    +

    Using Context

    +

    Sometimes, some state needs to be shared between multiple components far down the tree, and passing it down through props is very inconvenient.

    +

    Suppose now that we want to implement a dark mode toggle for our app. To achieve this, we will make every component select styling depending on whether dark mode is enabled or not.

    +
    +

    Note: we're choosing this approach for the sake of an example. There are better ways to implement dark mode (e.g. using CSS variables). Let's pretend CSS variables don't exist – welcome to 2013!

    +
    +

    Now, we could write another use_state in the top component, and pass is_dark_mode down to every component through props. But think about what will happen as the app grows in complexity – almost every component that renders any CSS is going to need to know if dark mode is enabled or not – so they'll all need the same dark mode prop. And every parent component will need to pass it down to them. Imagine how messy and verbose that would get, especially if we had components several levels deep!

    +

    Dioxus offers a better solution than this "prop drilling" – providing context. The use_context_provider hook is similar to use_ref, but it makes it available through use_context for all children components.

    +

    First, we have to create a struct for our dark mode configuration:

    +
    
    +#![allow(unused)]
    +fn main() {
    +struct DarkMode(bool);
    +}
    +
    +

    Now, in a top-level component (like App), we can provide the DarkMode context to all children components:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use_shared_state_provider(cx, || DarkMode(false));
    +}
    +
    +

    As a result, any child component of App (direct or not), can access the DarkMode context.

    +
    
    +#![allow(unused)]
    +fn main() {
    +let dark_mode_context = use_shared_state::<DarkMode>(cx);
    +}
    +
    +
    +

    use_context returns Option<UseSharedState<DarkMode>> here. If the context has been provided, the value is Some(UseSharedState<DarkMode>), which you can call .read or .write on, similarly to UseRef. Otherwise, the value is None.

    +
    +

    For example, here's how we would implement the dark mode toggle, which both reads the context (to determine what color it should render) and writes to it (to toggle dark mode):

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub fn DarkModeToggle(cx: Scope) -> Element {
    +    let dark_mode = use_shared_state::<DarkMode>(cx).unwrap();
    +
    +    let style = if dark_mode.read().0 {
    +        "color:white"
    +    } else {
    +        ""
    +    };
    +
    +    cx.render(rsx!(label {
    +        style: "{style}",
    +        "Dark Mode",
    +        input {
    +            r#type: "checkbox",
    +            oninput: move |event| {
    +                let is_enabled = event.value == "true";
    +                dark_mode.write().0 = is_enabled;
    +            },
    +        },
    +    }))
    +}
    +}
    +
    +

    Custom Hooks

    +

    Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own.

    +

    When writing your hook, you can make a function that accepts cx: &ScopeState as a parameter to accept a scope with any Props.

    +

    Composing Hooks

    +

    To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook.

    +

    For example, if many components need to access an AppSettings struct, you can create a "shortcut" hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn use_settings(cx: &ScopeState) -> &UseSharedState<AppSettings> {
    +    use_shared_state::<AppSettings>(cx).expect("App settings not provided")
    +}
    +}
    +
    +

    Or if you want to wrap a hook that persists reloads with the storage API, you can build on top of the use_ref hook to work with mutable state:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use gloo_storage::{LocalStorage, Storage};
    +use serde::{de::DeserializeOwned, Serialize};
    +
    +/// A persistent storage hook that can be used to store data across application reloads.
    +#[allow(clippy::needless_return)]
    +pub fn use_persistent<T: Serialize + DeserializeOwned + Default + 'static>(
    +    cx: &ScopeState,
    +    // A unique key for the storage entry
    +    key: impl ToString,
    +    // A function that returns the initial value if the storage entry is empty
    +    init: impl FnOnce() -> T,
    +) -> &UsePersistent<T> {
    +    // Use the use_ref hook to create a mutable state for the storage entry
    +    let state = use_ref(cx, move || {
    +        // This closure will run when the hook is created
    +        let key = key.to_string();
    +        let value = LocalStorage::get(key.as_str()).ok().unwrap_or_else(init);
    +        StorageEntry { key, value }
    +    });
    +
    +    // Wrap the state in a new struct with a custom API
    +    // Note: We use use_hook here so that this hook is easier to use in closures in the rsx. Any values with the same lifetime as the ScopeState can be used in the closure without cloning.
    +    cx.use_hook(|| UsePersistent {
    +        inner: state.clone(),
    +    })
    +}
    +
    +struct StorageEntry<T> {
    +    key: String,
    +    value: T,
    +}
    +
    +/// Storage that persists across application reloads
    +pub struct UsePersistent<T: 'static> {
    +    inner: UseRef<StorageEntry<T>>,
    +}
    +
    +impl<T: Serialize + DeserializeOwned + Clone + 'static> UsePersistent<T> {
    +    /// Returns a reference to the value
    +    pub fn get(&self) -> T {
    +        self.inner.read().value.clone()
    +    }
    +
    +    /// Sets the value
    +    pub fn set(&self, value: T) {
    +        let mut inner = self.inner.write();
    +        // Write the new value to local storage
    +        LocalStorage::set(inner.key.as_str(), &value);
    +        inner.value = value;
    +    }
    +}
    +}
    +
    +

    Custom Hook Logic

    +

    You can use cx.use_hook to build your own hooks. In fact, this is what all the standard hooks are built on!

    +

    use_hook accepts a single closure for initializing the hook. It will be only run the first time the component is rendered. The return value of that closure will be used as the value of the hook – Dioxus will take it, and store it for as long as the component is alive. On every render (not just the first one!), you will get a reference to this value.

    +
    +

    Note: You can implement Drop for your hook value – it will be dropped then the component is unmounted (no longer in the UI)

    +
    +

    Inside the initialization closure, you will typically make calls to other cx methods. For example:

    +
      +
    • The use_state hook tracks state in the hook value, and uses cx.schedule_update to make Dioxus re-render the component whenever it changes.
    • +
    +

    Here is a simplified implementation of the use_state hook:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use std::cell::RefCell;
    +use std::rc::Rc;
    +use std::sync::Arc;
    +
    +#[derive(Clone)]
    +struct UseState<T> {
    +    value: Rc<RefCell<T>>,
    +    update: Arc<dyn Fn()>,
    +}
    +
    +fn my_use_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> &UseState<T> {
    +    cx.use_hook(|| {
    +        // The update function will trigger a re-render in the component cx is attached to
    +        let update = cx.schedule_update();
    +        // Create the initial state
    +        let value = Rc::new(RefCell::new(init()));
    +
    +        UseState { value, update }
    +    })
    +}
    +
    +impl<T: Clone> UseState<T> {
    +    fn get(&self) -> T {
    +        self.value.borrow().clone()
    +    }
    +
    +    fn set(&self, value: T) {
    +        // Update the state
    +        *self.value.borrow_mut() = value;
    +        // Trigger a re-render on the component the state is from
    +        (self.update)();
    +    }
    +}
    +}
    +
    +
      +
    • The use_context hook calls cx.consume_context (which would be expensive to call on every render) to get some context from the scope
    • +
    +

    Here is an implementation of the use_context and use_context_provider hooks:

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> {
    +    cx.use_hook(|| cx.consume_context::<T>()).as_ref()
    +}
    +
    +pub fn use_context_provider<T: 'static + Clone>(cx: &ScopeState, f: impl FnOnce() -> T) -> &T {
    +    cx.use_hook(|| {
    +        let val = f();
    +        // Provide the context state to the scope
    +        cx.provide_context(val.clone());
    +        val
    +    })
    +}
    +
    +}
    +
    +

    Hook Anti-Patterns

    +

    When writing a custom hook, you should avoid the following anti-patterns:

    +
      +
    • !Clone Hooks: To allow hooks to be used within async blocks, the hooks must be Clone. To make a hook clone, you can wrap data in Rc or Arc and avoid lifetimes in hooks.
    • +
    +

    This version of use_state may seem more efficient, but it is not cloneable:

    +
    
    +#![allow(unused)]
    +fn main() {
    +use std::cell::RefCell;
    +use std::rc::Rc;
    +use std::sync::Arc;
    +
    +struct UseState<'a, T> {
    +    value: &'a RefCell<T>,
    +    update: Arc<dyn Fn()>,
    +}
    +
    +fn my_use_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> UseState<T> {
    +    // The update function will trigger a re-render in the component cx is attached to
    +    let update = cx.schedule_update();
    +    // Create the initial state
    +    let value = cx.use_hook(|| RefCell::new(init()));
    +
    +    UseState { value, update }
    +}
    +
    +impl<T: Clone> UseState<'_, T> {
    +    fn get(&self) -> T {
    +        self.value.borrow().clone()
    +    }
    +
    +    fn set(&self, value: T) {
    +        // Update the state
    +        *self.value.borrow_mut() = value;
    +        // Trigger a re-render on the component the state is from
    +        (self.update)();
    +    }
    +}
    +}
    +
    +

    If we try to use this hook in an async block, we will get a compile error:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn FutureComponent(cx: &ScopeState) -> Element {
    +    let my_state = my_use_state(cx, || 0);
    +    cx.spawn({
    +        to_owned![my_state];
    +        async move {
    +            my_state.set(1);
    +        }
    +    });
    +
    +    todo!()
    +}
    +}
    +
    +

    But with the original version, we can use it in an async block:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn FutureComponent(cx: &ScopeState) -> Element {
    +    let my_state = use_state(cx, || 0);
    +    cx.spawn({
    +        to_owned![my_state];
    +        async move {
    +            my_state.set(1);
    +        }
    +    });
    +
    +    todo!()
    +}
    +}
    +
    +

    Dynamic Rendering

    +

    Sometimes you want to render different things depending on the state/props. With Dioxus, just describe what you want to see using Rust control flow – the framework will take care of making the necessary changes on the fly if the state or props change!

    +

    Conditional Rendering

    +

    To render different elements based on a condition, you could use an if-else statement:

    +
    
    +#![allow(unused)]
    +fn main() {
    +if *is_logged_in {
    +    cx.render(rsx! {
    +        "Welcome!"
    +        button {
    +            onclick: move |_| on_log_out.call(()),
    +            "Log Out",
    +        }
    +    })
    +} else {
    +    cx.render(rsx! {
    +        button {
    +            onclick: move |_| on_log_in.call(()),
    +            "Log In",
    +        }
    +    })
    +}
    +}
    +
    +
    +

    You could also use match statements, or any Rust function to conditionally render different things.

    +
    +

    Improving the if-else Example

    +

    You may have noticed some repeated code in the if-else example above. Repeating code like this is both bad for maintainability and performance. Dioxus will skip diffing static elements like the button, but when switching between multiple rsx calls it cannot perform this optimization. For this example either approach is fine, but for components with large parts that are reused between conditionals, it can be more of an issue.

    +

    We can improve this example by splitting up the dynamic parts and inserting them where they are needed.

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx! {
    +    // We only render the welcome message if we are logged in
    +    // You can use if statements in the middle of a render block to conditionally render elements
    +    if *is_logged_in {
    +        // Notice the body of this if statment is rsx code, not an expression
    +        "Welcome!"
    +    }
    +    button {
    +        // depending on the value of `is_logged_in`, we will call a different event handler
    +        onclick: move |_| if *is_logged_in {
    +            on_log_in.call(())
    +        }
    +        else{
    +            on_log_out.call(())
    +        },
    +        if *is_logged_in {
    +            // if we are logged in, the button should say "Log Out"
    +            "Log Out"
    +        } else {
    +            // if we are not logged in, the button should say "Log In"
    +            "Log In"
    +        }
    +    }
    +})
    +}
    +
    +

    Inspecting Element props

    +

    Since Element is a Option<VNode>, components accepting Element as a prop can inspect its contents, and render different things based on that. Example:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
    +    match cx.props.children {
    +        Some(VNode { dynamic_nodes, .. }) => {
    +            todo!("render some stuff")
    +        }
    +        _ => {
    +            todo!("render some other stuff")
    +        }
    +    }
    +}
    +}
    +
    +

    You can't mutate the Element, but if you need a modified version of it, you can construct a new one based on its attributes/children/etc.

    +

    Rendering Nothing

    +

    To render nothing, you can return None from a component. This is useful if you want to conditionally hide something:

    +
    
    +#![allow(unused)]
    +fn main() {
    +if *is_logged_in {
    +    return None;
    +}
    +
    +cx.render(rsx! {
    +    a {
    +        "You must be logged in to comment"
    +    }
    +})
    +}
    +
    +

    This works because the Element type is just an alias for Option<VNode>

    +
    +

    Again, you may use a different method to conditionally return None. For example the boolean's then() function could be used.

    +
    +

    Rendering Lists

    +

    Often, you'll want to render a collection of components. For example, you might want to render a list of all comments on a post.

    +

    For this, Dioxus accepts iterators that produce Elements. So we need to:

    +
      +
    • Get an iterator over all of our items (e.g., if you have a Vec of comments, iterate over it with iter())
    • +
    • .map the iterator to convert each item into a LazyNode using rsx!(...) +
        +
      • Add a unique key attribute to each iterator item
      • +
      +
    • +
    • Include this iterator in the final RSX (or use it inline)
    • +
    +

    Example: suppose you have a list of comments you want to render. Then, you can render them like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let comment_field = use_state(cx, String::new);
    +let mut next_id = use_state(cx, || 0);
    +let comments = use_ref(cx, Vec::<Comment>::new);
    +
    +let comments_lock = comments.read();
    +let comments_rendered = comments_lock.iter().map(|comment| {
    +    rsx!(CommentComponent {
    +        key: "{comment.id}",
    +        comment: comment.clone(),
    +    })
    +});
    +
    +cx.render(rsx!(
    +    form {
    +        onsubmit: move |_| {
    +            comments.write().push(Comment {
    +                content: comment_field.get().clone(),
    +                id: *next_id.get(),
    +            });
    +            next_id += 1;
    +
    +            comment_field.set(String::new());
    +        },
    +        input {
    +            value: "{comment_field}",
    +            oninput: |event| comment_field.set(event.value.clone()),
    +        }
    +        input {
    +            r#type: "submit",
    +        }
    +    },
    +    comments_rendered,
    +))
    +}
    +
    +

    Inline for loops

    +

    Because of how common it is to render a list of items, Dioxus provides a shorthand for this. Instead of using .iter, .map, and rsx, you can use a for` loop with a body of rsx code:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let comment_field = use_state(cx, String::new);
    +let mut next_id = use_state(cx, || 0);
    +let comments = use_ref(cx, Vec::<Comment>::new);
    +
    +cx.render(rsx!(
    +    form {
    +        onsubmit: move |_| {
    +            comments.write().push(Comment {
    +                content: comment_field.get().clone(),
    +                id: *next_id.get(),
    +            });
    +            next_id += 1;
    +
    +            comment_field.set(String::new());
    +        },
    +        input {
    +            value: "{comment_field}",
    +            oninput: |event| comment_field.set(event.value.clone()),
    +        }
    +        input {
    +            r#type: "submit",
    +        }
    +    },
    +    for comment in &*comments.read() {
    +        // Notice the body of this for loop is rsx code, not an expression
    +        CommentComponent {
    +            key: "{comment.id}",
    +            comment: comment.clone(),
    +        }
    +    }
    +))
    +}
    +
    +

    The key Attribute

    +

    Every time you re-render your list, Dioxus needs to keep track of which items go where to determine what updates need to be made to the UI.

    +

    For example, suppose the CommentComponent had some state – e.g. a field where the user typed in a reply. If the order of comments suddenly changes, Dioxus needs to correctly associate that state with the same comment – otherwise, the user will end up replying to a different comment!

    +

    To help Dioxus keep track of list items, we need to associate each item with a unique key. In the example above, we dynamically generated the unique key. In real applications, it's more likely that the key will come from e.g. a database ID. It doesn't matter where you get the key from, as long as it meets the requirements:

    +
      +
    • Keys must be unique in a list
    • +
    • The same item should always get associated with the same key
    • +
    • Keys should be relatively small (i.e. converting the entire Comment structure to a String would be a pretty bad key) so they can be compared efficiently
    • +
    +

    You might be tempted to use an item's index in the list as its key. That’s what Dioxus will use if you don’t specify a key at all. This is only acceptable if you can guarantee that the list is constant – i.e., no re-ordering, additions, or deletions.

    +
    +

    Note that if you pass the key to a component you've made, it won't receive the key as a prop. It’s only used as a hint by Dioxus itself. If your component needs an ID, you have to pass it as a separate prop.

    +
    +

    Router

    +

    In many of your apps, you'll want to have different "scenes". For a webpage, these scenes might be the different webpages with their own content. For a desktop app, these scenes might be different views in your app.

    +

    To unify these platforms, Dioxus provides a first-party solution for scene management called Dioxus Router.

    +

    What is it?

    +

    For an app like the Dioxus landing page (https://dioxuslabs.com), we want to have several different scenes:

    +
      +
    • Homepage
    • +
    • Blog
    • +
    +

    Each of these scenes is independent – we don't want to render both the homepage and blog at the same time.

    +

    The Dioxus router makes it easy to create these scenes. To make sure we're using the router, add the dioxus-router package to your Cargo.toml.

    +
    cargo add dioxus-router
    +
    +

    Using the router

    +

    Unlike other routers in the Rust ecosystem, our router is built declaratively. This makes it possible to compose our app layout simply by arranging components.

    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    // All of our routes will be rendered inside this Router component
    +    Router {
    +        // if the current location is "/home", render the Home component
    +        Route { to: "/home", Home {} }
    +        // if the current location is "/blog", render the Blog component
    +        Route { to: "/blog", Blog {} }
    +    }
    +}
    +}
    +
    +

    Whenever we visit this app, we will get either the Home component or the Blog component rendered depending on which route we enter at. If neither of these routes match the current location, then nothing will render.

    +

    We can fix this one of two ways:

    +
      +
    • A fallback 404 page
    • +
    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Router {
    +        Route { to: "/home", Home {} }
    +        Route { to: "/blog", Blog {} }
    +        //  if the current location doesn't match any of the above routes, render the NotFound component
    +        Route { to: "", NotFound {} }
    +    }
    +}
    +}
    +
    +
      +
    • Redirect 404 to home
    • +
    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Router {
    +        Route { to: "/home", Home {} }
    +        Route { to: "/blog", Blog {} }
    +        //  if the current location doesn't match any of the above routes, redirect to "/home"
    +        Redirect { from: "", to: "/home" }
    +    }
    +}
    +}
    +
    + +

    For our app to navigate these routes, we can provide clickable elements called Links. These simply wrap <a> elements that, when clicked, navigate the app to the given location.

    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!{
    +    Link {
    +        to: "/home",
    +        "Go home!"
    +    }
    +}
    +}
    +
    +

    More reading

    +

    This page is just a very brief overview of the router. For more information, check out the router book or some of the router examples.

    +

    Working with Async

    +

    Often, apps need to interact with file systems, network interfaces, hardware, or timers. This chapter provides an overview of using async code in Dioxus.

    +

    The Runtime

    +

    By default, Dioxus-Desktop ships with the Tokio runtime and automatically sets everything up for you. This is currently not configurable, though it would be easy to write an integration for Dioxus desktop that uses a different asynchronous runtime.

    +

    Dioxus is not currently thread-safe, so any async code you write does not need to be Send/Sync. That means that you can use non-thread-safe structures like Cell, Rc, and RefCell.

    +

    UseFuture

    +

    use_future lets you run an async closure, and provides you with its result.

    +

    For example, we can make an API request (using reqwest) inside use_future:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let future = use_future(cx, (), |_| async move {
    +    reqwest::get("https://dog.ceo/api/breeds/image/random")
    +        .await
    +        .unwrap()
    +        .json::<ApiResponse>()
    +        .await
    +});
    +}
    +
    +

    The code inside use_future will be submitted to the Dioxus scheduler once the component has rendered.

    +

    We can use .value() to get the result of the future. On the first run, since there's no data ready when the component loads, its value will be None. However, once the future is finished, the component will be re-rendered and the value will now be Some(...), containing the return value of the closure.

    +

    We can then render that result:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(match future.value() {
    +    Some(Ok(response)) => rsx! {
    +        button {
    +            onclick: move |_| future.restart(),
    +            "Click to fetch another doggo"
    +        }
    +        div {
    +            img {
    +                max_width: "500px",
    +                max_height: "500px",
    +                src: "{response.image_url}",
    +            }
    +        }
    +    },
    +    Some(Err(_)) => rsx! { div { "Loading dogs failed" } },
    +    None => rsx! { div { "Loading dogs..." } },
    +})
    +}
    +
    +

    Restarting the Future

    +

    The UseFuture handle provides a restart method. It can be used to execute the future again, producing a new value.

    +

    Dependencies

    +

    Often, you will need to run the future again every time some value (e.g. a prop) changes. Rather than calling restart manually, you can provide a tuple of "dependencies" to the hook. It will automatically re-run the future when any of those dependencies change. Example:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let future = use_future(cx, (breed,), |(breed,)| async move {
    +    reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
    +        .await
    +        .unwrap()
    +        .json::<ApiResponse>()
    +        .await
    +});
    +}
    +
    +

    Coroutines

    +

    Another tool in your async toolbox are coroutines. Coroutines are futures that can be manually stopped, started, paused, and resumed.

    +

    Like regular futures, code in a coroutine will run until the next await point before yielding. This low-level control over asynchronous tasks is quite powerful, allowing for infinitely looping tasks like WebSocket polling, background timers, and other periodic actions.

    +

    use_coroutine

    +

    The use_coroutine hook allows you to create a coroutine. Most coroutines we write will be polling loops using async/await.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn app(cx: Scope) -> Element {
    +    let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
    +        // Connect to some sort of service
    +        let mut conn = connect_to_ws_server().await;
    +
    +        // Wait for data on the service
    +        while let Some(msg) = conn.next().await {
    +            // handle messages
    +        }
    +    });
    +}
    +}
    +
    +

    For many services, a simple async loop will handle the majority of use cases.

    +

    However, if we want to temporarily disable the coroutine, we can "pause" it using the pause method, and "resume" it using the resume method:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
    +    // code for syncing
    +});
    +
    +if sync.is_running() {
    +    cx.render(rsx!{
    +        button {
    +            onclick: move |_| sync.pause(),
    +            "Disable syncing"
    +        }
    +    })
    +} else {
    +    cx.render(rsx!{
    +        button {
    +            onclick: move |_| sync.resume(),
    +            "Enable syncing"
    +        }
    +    })
    +}
    +}
    +
    +

    This pattern is where coroutines are extremely useful – instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.

    +

    Yielding Values

    +

    To yield values from a coroutine, simply bring in a UseState handle and set the value whenever your coroutine completes its work.

    +

    The future must be 'static – so any values captured by the task cannot carry any references to cx, such as a UseState.

    +

    You can use to_owned to create a clone of the hook handle which can be moved into the async closure.

    +
    
    +#![allow(unused)]
    +fn main() {
    +let sync_status = use_state(cx, || Status::Launching);
    +let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
    +    let sync_status = sync_status.to_owned();
    +    async move {
    +        loop {
    +            delay_ms(1000).await;
    +            sync_status.set(Status::Working);
    +        }
    +    }
    +})
    +}
    +
    +

    To make this a bit less verbose, Dioxus exports the to_owned! macro which will create a binding as shown above, which can be quite helpful when dealing with many values.

    +
    
    +#![allow(unused)]
    +fn main() {
    +let sync_status = use_state(cx, || Status::Launching);
    +let load_status = use_state(cx, || Status::Launching);
    +let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
    +    to_owned![sync_status, load_status];
    +    async move {
    +        // ...
    +    }
    +})
    +}
    +
    +

    Sending Values

    +

    You might've noticed the use_coroutine closure takes an argument called rx. What is that? Well, a common pattern in complex apps is to handle a bunch of async code at once. With libraries like Redux Toolkit, managing multiple promises at once can be challenging and a common source of bugs.

    +

    With Coroutines, we can centralize our async logic. The rx parameter is an Channel that allows code external to the coroutine to send data into the coroutine. Instead of looping on an external service, we can loop on the channel itself, processing messages from within our app without needing to spawn a new future. To send data into the coroutine, we would call "send" on the handle.

    +
    
    +#![allow(unused)]
    +fn main() {
    +use futures_util::stream::StreamExt;
    +
    +enum ProfileUpdate {
    +    SetUsername(String),
    +    SetAge(i32)
    +}
    +
    +let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
    +    let mut server = connect_to_server().await;
    +
    +    while let Ok(msg) = rx.next().await {
    +        match msg {
    +            ProfileUpdate::SetUsername(name) => server.update_username(name).await,
    +            ProfileUpdate::SetAge(age) => server.update_age(age).await,
    +        }
    +    }
    +});
    +
    +
    +cx.render(rsx!{
    +    button {
    +        onclick: move |_| profile.send(ProfileUpdate::SetUsername("Bob".to_string())),
    +        "Update username"
    +    }
    +})
    +}
    +
    +
    +

    Note: In order to use/run the rx.next().await statement you will need to extend the [Stream] trait (used by [UnboundedReceiver]) by adding 'futures_util' as a dependency to your project and adding the use futures_util::stream::StreamExt;.

    +
    +

    For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app.

    +
    
    +#![allow(unused)]
    +fn main() {
    +let profile = use_coroutine(cx, profile_service);
    +let editor = use_coroutine(cx, editor_service);
    +let sync = use_coroutine(cx, sync_service);
    +
    +async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
    +    // do stuff
    +}
    +
    +async fn sync_service(rx: UnboundedReceiver<SyncCommand>) {
    +    // do stuff
    +}
    +
    +async fn editor_service(rx: UnboundedReceiver<EditorCommand>) {
    +    // do stuff
    +}
    +}
    +
    +

    We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state within a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your actual state does not need to be tied up in a system like Fermi or Redux – the only Atoms that need to exist are those that are used to drive the display/UI.

    +
    
    +#![allow(unused)]
    +fn main() {
    +static USERNAME: Atom<String> = |_| "default".to_string();
    +
    +fn app(cx: Scope) -> Element {
    +    let atoms = use_atom_root(cx);
    +
    +    use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
    +
    +    cx.render(rsx!{
    +        Banner {}
    +    })
    +}
    +
    +fn Banner(cx: Scope) -> Element {
    +    let username = use_read(cx, USERNAME);
    +
    +    cx.render(rsx!{
    +        h1 { "Welcome back, {username}" }
    +    })
    +}
    +}
    +
    +

    Now, in our sync service, we can structure our state however we want. We only need to update the view values when ready.

    +
    
    +#![allow(unused)]
    +fn main() {
    +use futures_util::stream::StreamExt;
    +
    +enum SyncAction {
    +    SetUsername(String),
    +}
    +
    +async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
    +    let username = atoms.write(USERNAME);
    +    let errors = atoms.write(ERRORS);
    +
    +    while let Ok(msg) = rx.next().await {
    +        match msg {
    +            SyncAction::SetUsername(name) => {
    +                if set_name_on_server(&name).await.is_ok() {
    +                    username.set(name);
    +                } else {
    +                    errors.make_mut().push("SetUsernameFailed");
    +                }
    +            }
    +        }
    +    }
    +}
    +}
    +
    +

    Automatic injection into the Context API

    +

    Coroutine handles are automatically injected through the context API. You can use the use_coroutine_handle hook with the message type as a generic to fetch a handle.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Child(cx: Scope) -> Element {
    +    let sync_task = use_coroutine_handle::<SyncAction>(cx);
    +
    +    sync_task.send(SyncAction::SetUsername);
    +}
    +}
    +
    +

    Spawning Futures

    +

    The use_future and use_coroutine hooks are useful if you want to unconditionally spawn the future. Sometimes, though, you'll want to only spawn a future in response to an event, such as a mouse click. For example, suppose you need to send a request when the user clicks a "log in" button. For this, you can use cx.spawn:

    +
    
    +#![allow(unused)]
    +fn main() {
    +    let logged_in = use_state(cx, || false);
    +
    +    let log_in = move |_| {
    +        cx.spawn({
    +            let logged_in = logged_in.to_owned();
    +
    +            async move {
    +                let resp = reqwest::Client::new()
    +                    .post("http://example.com/login")
    +                    .send()
    +                    .await;
    +
    +                match resp {
    +                    Ok(_data) => {
    +                        println!("Login successful!");
    +                        logged_in.set(true);
    +                    }
    +                    Err(_err) => {
    +                        println!(
    +                            "Login failed - you need a login server running on localhost:8080."
    +                        )
    +                    }
    +                }
    +            }
    +        });
    +    };
    +
    +    cx.render(rsx! {
    +        button {
    +            onclick: log_in,
    +            "Login",
    +        }
    +    })
    +}
    +
    +
    +

    Note: spawn will always spawn a new future. You most likely don't want to call it on every render.

    +
    +

    Calling spawn will give you a JoinHandle which lets you cancel or pause the future.

    +

    Spawning Tokio Tasks

    +

    Sometimes, you might want to spawn a background task that needs multiple threads or talk to hardware that might block your app code. In these cases, we can directly spawn a Tokio task from our future. For Dioxus-Desktop, your task will be spawned onto Tokio's Multithreaded runtime:

    +
    
    +#![allow(unused)]
    +fn main() {
    +        cx.spawn(async {
    +            let _ = tokio::spawn(async {}).await;
    +
    +            let _ = tokio::task::spawn_local(async {
    +                // some !Send work
    +            })
    +            .await;
    +        });
    +}
    +
    +

    Best Practices

    +

    Reusable Components

    +

    As much as possible, break your code down into small, reusable components and hooks, instead of implementing large chunks of the UI in a single component. This will help you keep the code maintainable – it is much easier to e.g. add, remove or re-order parts of the UI if it is organized in components.

    +

    Organize your components in modules to keep the codebase easy to navigate!

    +

    Minimize State Dependencies

    +

    While it is possible to share state between components, this should only be done when necessary. Any component that is associated with a particular state object needs to be re-rendered when that state changes. For this reason:

    +
      +
    • Keep state local to a component if possible
    • +
    • When sharing state through props, only pass down the specific data necessary
    • +
    +

    Error handling

    +

    A selling point of Rust for web development is the reliability of always knowing where errors can occur and being forced to handle them

    +

    However, we haven't talked about error handling at all in this guide! In this chapter, we'll cover some strategies in handling errors to ensure your app never crashes.

    +

    The simplest – returning None

    +

    Astute observers might have noticed that Element is actually a type alias for Option<VNode>. You don't need to know what a VNode is, but it's important to recognize that we could actually return nothing at all:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    None
    +}
    +}
    +
    +

    This lets us add in some syntactic sugar for operations we think shouldn't fail, but we're still not confident enough to "unwrap" on.

    +
    +

    The nature of Option<VNode> might change in the future as the try trait gets upgraded.

    +
    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    // immediately return "None"
    +    let name = cx.use_hook(|_| Some("hi"))?;
    +}
    +}
    +
    +

    Early return on result

    +

    Because Rust can't accept both Options and Results with the existing try infrastructure, you'll need to manually handle Results. This can be done by converting them into Options or by explicitly handling them.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn App(cx: Scope) -> Element {
    +    // Convert Result to Option
    +    let name = cx.use_hook(|_| "1.234").parse().ok()?;
    +
    +
    +    // Early return
    +    let count = cx.use_hook(|_| "1.234");
    +    let val = match count.parse() {
    +        Ok(val) => val
    +        Err(err) => return cx.render(rsx!{ "Parsing failed" })
    +    };
    +}
    +}
    +
    +

    Notice that while hooks in Dioxus do not like being called in conditionals or loops, they are okay with early returns. Returning an error state early is a completely valid way of handling errors.

    +

    Match results

    +

    The next "best" way of handling errors in Dioxus is to match on the error locally. This is the most robust way of handling errors, though it doesn't scale to architectures beyond a single component.

    +

    To do this, we simply have an error state built into our component:

    +
    
    +#![allow(unused)]
    +fn main() {
    +let err = use_state(cx, || None);
    +}
    +
    +

    Whenever we perform an action that generates an error, we'll set that error state. We can then match on the error in a number of ways (early return, return Element, etc).

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Commandline(cx: Scope) -> Element {
    +    let error = use_state(cx, || None);
    +
    +    cx.render(match *error {
    +        Some(error) => rsx!(
    +            h1 { "An error occured" }
    +        )
    +        None => rsx!(
    +            input {
    +                oninput: move |_| error.set(Some("bad thing happened!")),
    +            }
    +        )
    +    })
    +}
    +}
    +
    +

    Passing error states through components

    +

    If you're dealing with a handful of components with minimal nesting, you can just pass the error handle into child components.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Commandline(cx: Scope) -> Element {
    +    let error = use_state(cx, || None);
    +
    +    if let Some(error) = **error {
    +        return cx.render(rsx!{ "An error occured" });
    +    }
    +
    +    cx.render(rsx!{
    +        Child { error: error.clone() }
    +        Child { error: error.clone() }
    +        Child { error: error.clone() }
    +        Child { error: error.clone() }
    +    })
    +}
    +}
    +
    +

    Much like before, our child components can manually set the error during their own actions. The advantage to this pattern is that we can easily isolate error states to a few components at a time, making our app more predictable and robust.

    +

    Going global

    +

    A strategy for handling cascaded errors in larger apps is through signaling an error using global state. This particular pattern involves creating an "error" context, and then setting it wherever relevant. This particular method is not as "sophisticated" as React's error boundary, but it is more fitting for Rust.

    +

    To get started, consider using a built-in hook like use_context and use_context_provider or Fermi. Of course, it's pretty easy to roll your own hook too.

    +

    At the "top" of our architecture, we're going to want to explicitly declare a value that could be an error.

    +
    
    +#![allow(unused)]
    +fn main() {
    +enum InputError {
    +    None,
    +    TooLong,
    +    TooShort,
    +}
    +
    +static INPUT_ERROR: Atom<InputError> = |_| InputError::None;
    +}
    +
    +

    Then, in our top level component, we want to explicitly handle the possible error state for this part of the tree.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn TopLevel(cx: Scope) -> Element {
    +    let error = use_read(cx, INPUT_ERROR);
    +
    +    match error {
    +        TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
    +        TooShort => return cx.render(rsx!{ "FAILED: Too Short!" }),
    +        _ => {}
    +    }
    +}
    +}
    +
    +

    Now, whenever a downstream component has an error in its actions, it can simply just set its own error state:

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn Commandline(cx: Scope) -> Element {
    +    let set_error = use_set(cx, INPUT_ERROR);
    +
    +    cx.render(rsx!{
    +        input {
    +            oninput: move |evt| {
    +                if evt.value.len() > 20 {
    +                    set_error(InputError::TooLong);
    +                }
    +            }
    +        }
    +    })
    +}
    +}
    +
    +

    This approach to error handling is best in apps that have "well defined" error states. Consider using a crate like thiserror or anyhow to simplify the generation of the error types.

    +

    This pattern is widely popular in many contexts and is particularly helpful whenever your code generates a non-recoverable error. You can gracefully capture these "global" error states without panicking or mucking up state.

    +

    Antipatterns

    +

    This example shows what not to do and provides a reason why a given pattern is considered an "AntiPattern". Most anti-patterns are considered wrong for performance or code re-usability reasons.

    +

    Unnecessarily Nested Fragments

    +

    Fragments don't mount a physical element to the DOM immediately, so Dioxus must recurse into its children to find a physical DOM node. This process is called "normalization". This means that deeply nested fragments make Dioxus perform unnecessary work. Prefer one or two levels of fragments / nested components until presenting a true DOM element.

    +

    Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing an API for registering shared state without the Context Provider pattern.

    +
    
    +#![allow(unused)]
    +fn main() {
    +    // ❌ Don't unnecessarily nest fragments
    +    let _ = cx.render(rsx!(
    +        Fragment {
    +            Fragment {
    +                Fragment {
    +                    Fragment {
    +                        Fragment {
    +                            div { "Finally have a real node!" }
    +                        }
    +                    }
    +                }
    +            }
    +        }
    +    ));
    +
    +    // ✅ Render shallow structures
    +    cx.render(rsx!(
    +        div { "Finally have a real node!" }
    +    ))
    +}
    +
    +

    Incorrect Iterator Keys

    +

    As described in the dynamic rendering chapter, list items must have unique keys that are associated with the same items across renders. This helps Dioxus associate state with the contained components and ensures good diffing performance. Do not omit keys, unless you know that the list will never change.

    +
    
    +#![allow(unused)]
    +fn main() {
    +    let data: &HashMap<_, _> = &cx.props.data;
    +
    +    // ❌ No keys
    +    cx.render(rsx! {
    +        ul {
    +            data.values().map(|value| rsx!(
    +                li { "List item: {value}" }
    +            ))
    +        }
    +    });
    +
    +    // ❌ Using index as keys
    +    cx.render(rsx! {
    +        ul {
    +            cx.props.data.values().enumerate().map(|(index, value)| rsx!(
    +                li { key: "{index}", "List item: {value}" }
    +            ))
    +        }
    +    });
    +
    +    // ✅ Using unique IDs as keys:
    +    cx.render(rsx! {
    +        ul {
    +            cx.props.data.iter().map(|(key, value)| rsx!(
    +                li { key: "{key}", "List item: {value}" }
    +            ))
    +        }
    +    })
    +}
    +
    +

    Avoid Interior Mutability in Props

    +

    While it is technically acceptable to have a Mutex or a RwLock in the props, they will be difficult to use.

    +

    Suppose you have a struct User containing the field username: String. If you pass a Mutex<User> prop to a UserComponent component, that component may wish to pass the username as a &str prop to a child component. However, it cannot pass that borrowed field down, since it only would live as long as the Mutex's lock, which belongs to the UserComponent function. Therefore, the component will be forced to clone the username field.

    +

    Avoid Updating State During Render

    +

    Every time you update the state, Dioxus needs to re-render the component – this is inefficient! Consider refactoring your code to avoid this.

    +

    Also, if you unconditionally update the state during render, it will be re-rendered in an infinite loop.

    +

    Publishing

    +

    Publishing

    +

    Congrats! You've made your first Dioxus app that actually does some pretty cool stuff. This app uses your operating system's WebView library, so it's portable to be distributed for other platforms.

    +

    In this section, we'll cover how to bundle your app for macOS, Windows, and Linux.

    +

    Install cargo-bundle

    +

    The first thing we'll do is install cargo-bundle. This extension to cargo will make it very easy to package our app for the various platforms.

    +

    According to the cargo-bundle github page,

    +

    "cargo-bundle is a tool used to generate installers or app bundles for GUI executables built with cargo. It can create .app bundles for Mac OS X and iOS, .deb packages for Linux, and .msi installers for Windows (note however that iOS and Windows support is still experimental). Support for creating .rpm packages (for Linux) and .apk packages (for Android) is still pending."

    +

    To install, simply run

    +

    cargo install cargo-bundle

    +

    Setting up your project

    +

    To get a project setup for bundling, we need to add some flags to our Cargo.toml file.

    +
    [package]
    +name = "example"
    +# ...other fields...
    +
    +[package.metadata.bundle]
    +name = "DogSearch"
    +identifier = "com.dogs.dogsearch"
    +version = "1.0.0"
    +copyright = "Copyright (c) Jane Doe 2016. All rights reserved."
    +category = "Developer Tool"
    +short_description = "Easily search for Dog photos"
    +long_description = """
    +This app makes it quick and easy to browse photos of dogs from over 200 bree
    +"""
    +
    +

    Building

    +

    Following cargo-bundle's instructions, we simply cargo-bundle --release to produce a final app with all the optimizations and assets builtin.

    +

    Once you've ran cargo-bundle --release, your app should be accessible in

    +

    target/release/bundle/<platform>/.

    +

    For example, a macOS app would look like this:

    +

    Published App

    +

    Nice! And it's only 4.8 Mb – extremely lean!! Because Dioxus leverages your platform's native WebView, Dioxus apps are extremely memory efficient and won't waste your battery.

    +
    +

    Note: not all CSS works the same on all platforms. Make sure to view your app's CSS on each platform – or web browser (Firefox, Chrome, Safari) before publishing.

    +
    +

    Publishing with Github Pages

    +

    To build our app and publish it to Github:

    +
      +
    • Make sure GitHub Pages is set up for your repo
    • +
    • Build your app with trunk build --release (include --public-url <repo-name> to update asset prefixes if using a project site)
    • +
    • Move your generated HTML/CSS/JS/Wasm from dist into the folder configured for Github Pages
    • +
    • Add and commit with git
    • +
    • Push to GitHub
    • +
    +

    Fullstack development

    +

    So far you have learned about three different approaches to target the web with Dioxus:

    + +

    Summary of Existing Approaches

    +

    Each approach has its tradeoffs:

    +

    Client-side rendering

    +
      +
    • +

      With Client side rendering, you send the entire content of your application to the client, and then the client generates all of the HTML of the page dynamically.

      +
    • +
    • +

      This means that the page will be blank until the JavaScript bundle has loaded and the application has initialized. This can result in slower first render times and makes the page less SEO-friendly.

      +
    • +
    +
    +

    SEO stands for Search Engine Optimization. It refers to the practice of making your website more likely to appear in search engine results. Search engines like Google and Bing use web crawlers to index the content of websites. Most of these crawlers are not able to run JavaScript, so they will not be able to index the content of your page if it is rendered client-side.

    +
    +
      +
    • Client-side rendered applications need to use weakly typed requests to communicate with the server
    • +
    +
    +

    Client-side rendering is a good starting point for most applications. It is well supported and makes it easy to communicate with the client/browser APIs

    +
    +

    Liveview

    +
      +
    • +

      Liveview rendering communicates with the server over a WebSocket connection. It essentially moves all of the work that Client-side rendering does to the server.

      +
    • +
    • +

      This makes it easy to communicate with the server, but more difficult to communicate with the client/browser APIS.

      +
    • +
    • +

      Each interaction also requires a message to be sent to the server and back which can cause issues with latency.

      +
    • +
    • +

      Because Liveview uses a websocket to render, the page will be blank until the WebSocket connection has been established and the first renderer has been sent form the websocket. Just like with client side rendering, this can make the page less SEO-friendly.

      +
    • +
    • +

      Because the page is rendered on the server and the page is sent to the client piece by piece, you never need to send the entire application to the client. The initial load time can be faster than client-side rendering with large applications because Liveview only needs to send a constant small websocket script regardless of the size of the application.

      +
    • +
    +
    +

    Liveview is a good fit for applications that already need to communicate with the server frequently (like real time collaborative apps), but don't need to communicate with as many client/browser APIs

    +
    +

    Server-side rendering

    +
      +
    • Server-side rendering generates all of the HTML of the page on the server before the page is sent to the client. This means that the page will be fully rendered when it is sent to the client. This results in a faster first render time and makes the page more SEO-friendly. However, it only works for static pages.
    • +
    +
    +

    Server-side rendering is not a good fit for purely static sites like a blog

    +
    +

    A New Approach

    +

    Each of these approaches has its tradeoffs. What if we could combine the best parts of each approach?

    +
      +
    • Fast initial render time like SSR
    • +
    • Works well with SEO like SSR
    • +
    • Type safe easy communication with the server like Liveview
    • +
    • Access to the client/browser APIs like Client-side rendering
    • +
    • Fast interactivity like Client-side rendering
    • +
    +

    We can achieve this by rendering the initial page on the server (SSR) and then taking over rendering on the client (Client-side rendering). Taking over rendering on the client is called hydration.

    +

    Finally, we can use server functions to communicate with the server in a type-safe way.

    +

    This approach uses both the dioxus-web and dioxus-ssr crates. To integrate those two packages and axum, warp, or salvo, Dioxus provides the dioxus-fullstack crate.

    +
    +

    This guide assumes you read the Web guide and installed the Dioxus-cli

    +
    +

    Getting Started

    +

    Setup

    +

    For this guide, we're going to show how to use Dioxus with Axum, but dioxus-fullstack also integrates with the Warp and Salvo web frameworks.

    +

    Make sure you have Rust and Cargo installed, and then create a new project:

    +
    cargo new --bin demo
    +cd demo
    +
    +

    Add dioxus and dioxus-fullstack as dependencies:

    +
    cargo add dioxus
    +cargo add dioxus-fullstack --features axum, ssr
    +
    +

    Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

    +
    cargo add tokio --features full
    +cargo add axum
    +
    +

    Your dependencies should look roughly like this:

    +
    [dependencies]
    +axum = "*"
    +dioxus = { version = "*" }
    +dioxus-fullstack = { version = "*", features = ["axum", "ssr"] }
    +tokio = { version = "*", features = ["full"] }
    +
    +

    Now, set up your Axum app to serve the Dioxus app.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +
    +#[tokio::main]
    +async fn main() {
    +    #[cfg(feature = "ssr")]
    +    {
    +        use dioxus_fullstack::prelude::*;
    +
    +        let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +        axum::Server::bind(&addr)
    +            .serve(
    +                axum::Router::new()
    +                    .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
    +                    .into_make_service(),
    +            )
    +            .await
    +            .unwrap();
    +    }
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, run your app with cargo run and open http://localhost:8080 in your browser. You should see a server-side rendered page with a counter.

    +

    Hydration

    +

    Right now, the page is static. We can't interact with the buttons. To fix this, we can hydrate the page with dioxus-web.

    +

    First, modify your Cargo.toml to include two features, one for the server called ssr, and one for the client called web.

    +
    [dependencies]
    +# Common dependancies
    +dioxus = { version = "*" }
    +dioxus-fullstack = { version = "*" }
    +
    +# Web dependancies
    +dioxus-web = { version = "*", features=["hydrate"], optional = true }
    +
    +# Server dependancies
    +axum = { version = "0.6.12", optional = true }
    +tokio = { version = "1.27.0", features = ["full"], optional = true }
    +
    +[features]
    +default = []
    +ssr = ["axum", "tokio", "dioxus-fullstack/axum"]
    +web = ["dioxus-web"]
    +
    +

    Next, we need to modify our main.rs to use either hydrate on the client or render on the server depending on the active features.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true));
    +    #[cfg(feature = "ssr")]
    +    {
    +        use dioxus_fullstack::prelude::*;
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see the same page as before, but now you can interact with the buttons!

    +

    Sycronizing props between the server and client

    +

    Let's make the initial count of the counter dynamic based on the current page.

    +

    Modifying the server

    +

    To do this, we must remove the serve_dioxus_application and replace it with a custom implementation of its four key functions:

    +
      +
    • Serve static WASM and JS files with serve_static_assets
    • +
    • Register server functions with register_server_fns (more information on server functions later)
    • +
    • Connect to the hot reload server with connect_hot_reload
    • +
    • A custom route that uses SSRState to server-side render the application
    • +
    +

    Modifying the client

    +

    The only thing we need to change on the client is the props. dioxus-fullstack will automatically serialize the props it uses to server render the app and send them to the client. In the client section of main.rs, we need to add get_root_props_from_document to deserialize the props before we hydrate the app.

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +use dioxus_fullstack::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_with_props(
    +        app,
    +        // Get the root props from the document
    +        get_root_props_from_document().unwrap_or_default(),
    +        dioxus_web::Config::new().hydrate(true),
    +    );
    +    #[cfg(feature = "ssr")]
    +    {
    +        use axum::extract::Path;
    +        use axum::extract::State;
    +        use axum::routing::get;
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            // Serve the dist folder with the static javascript and WASM files created by the dixous CLI
    +                            .serve_static_assets("./dist")
    +                            // Register server functions
    +                            .register_server_fns("")
    +                            // Connect to the hot reload server in debug mode
    +                            .connect_hot_reload()
    +                            // Render the application. This will serialize the root props (the intial count) into the HTML
    +                            .route(
    +                                "/",
    +                                get(move | State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            0,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            // Render the application with a different intial count
    +                            .route(
    +                                "/:initial_count",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            .with_state(SSRState::default())
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope<usize>) -> Element {
    +    let mut count = use_state(cx, || *cx.props);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. Navigate to http://localhost:8080/1 and you should see the counter start at 1. Navigate to http://localhost:8080/2 and you should see the counter start at 2.

    +

    Communicating with the server

    +

    dixous-server provides server functions that allow you to call an automatically generated API on the server from the client as if it were a local function.

    +

    To make a server function, simply add the #[server(YourUniqueType)] attribute to a function. The function must:

    +
      +
    • Be an async function
    • +
    • Have arguments and a return type that both implement serialize and deserialize (with serde).
    • +
    • Return a Result with an error type of ServerFnError
    • +
    +

    You must call register on the type you passed into the server macro in your main function before starting your server to tell Dioxus about the server function.

    +

    Let's continue building on the app we made in the getting started guide. We will add a server function to our app that allows us to double the count on the server.

    +

    First, add serde as a dependency:

    +
    cargo add serde
    +
    +

    Next, add the server function to your main.rs:

    +
    #![allow(non_snake_case, unused)]
    +use dioxus::prelude::*;
    +use dioxus_fullstack::prelude::*;
    +
    +fn main() {
    +    #[cfg(feature = "web")]
    +    dioxus_web::launch_with_props(
    +        app,
    +        // Get the root props from the document
    +        get_root_props_from_document().unwrap_or_default(),
    +        dioxus_web::Config::new().hydrate(true),
    +    );
    +    #[cfg(feature = "ssr")]
    +    {
    +        use axum::extract::Path;
    +        use axum::extract::State;
    +        use axum::routing::get;
    +
    +        // Register the server function before starting the server
    +        DoubleServer::register().unwrap();
    +
    +        tokio::runtime::Runtime::new()
    +            .unwrap()
    +            .block_on(async move {
    +                let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
    +                axum::Server::bind(&addr)
    +                    .serve(
    +                        axum::Router::new()
    +                            // Serve the dist folder with the static javascript and WASM files created by the dixous CLI
    +                            .serve_static_assets("./dist")
    +                            // Register server functions
    +                            .register_server_fns("")
    +                            // Connect to the hot reload server in debug mode
    +                            .connect_hot_reload()
    +                            // Render the application. This will serialize the root props (the intial count) into the HTML
    +                            .route(
    +                                "/",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            // Render the application with a different intial count
    +                            .route(
    +                                "/:initial_count",
    +                                get(move |Path(intial_count): Path<usize>, State(ssr_state): State<SSRState>| async move { axum::body::Full::from(
    +                                    ssr_state.render(
    +                                        &ServeConfigBuilder::new(
    +                                            app,
    +                                            intial_count,
    +                                        )
    +                                        .build(),
    +                                    )
    +                                )}),
    +                            )
    +                            .with_state(SSRState::default())
    +                            .into_make_service(),
    +                    )
    +                    .await
    +                    .unwrap();
    +            });
    +    }
    +}
    +
    +fn app(cx: Scope<usize>) -> Element {
    +    let mut count = use_state(cx, || *cx.props);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +        button {
    +            onclick: move |_| {
    +                to_owned![count];
    +                async move {
    +                    // Call the server function just like a local async function
    +                    if let Ok(new_count) = double_server(*count.current()).await {
    +                        count.set(new_count);
    +                    }
    +                }
    +            },
    +            "Double"
    +        }
    +    })
    +}
    +
    +#[server(DoubleServer)]
    +async fn double_server(number: usize) -> Result<usize, ServerFnError> {
    +    // Perform some expensive computation or access a database on the server
    +    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    +    let result = number * 2;
    +    println!("server calculated {result}");
    +    Ok(result)
    +}
    +
    +

    Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see a new button that multiplies the count by 2.

    +

    Conclusion

    +

    That's it! You've created a full-stack Dioxus app. You can find more examples of full-stack apps and information about how to integrate with other frameworks and desktop renderers in the dioxus-fullstack examples directory.

    +

    Custom Renderer

    +

    Dioxus is an incredibly portable framework for UI development. The lessons, knowledge, hooks, and components you acquire over time can always be used for future projects. However, sometimes those projects cannot leverage a supported renderer or you need to implement your own better renderer.

    +

    Great news: the design of the renderer is entirely up to you! We provide suggestions and inspiration with the 1st party renderers, but only really require processing Mutations and sending UserEvents.

    +

    The specifics:

    +

    Implementing the renderer is fairly straightforward. The renderer needs to:

    +
      +
    1. Handle the stream of edits generated by updates to the virtual DOM
    2. +
    3. Register listeners and pass events into the virtual DOM's event system
    4. +
    +

    Essentially, your renderer needs to process edits and generate events to update the VirtualDOM. From there, you'll have everything needed to render the VirtualDOM to the screen.

    +

    Internally, Dioxus handles the tree relationship, diffing, memory management, and the event system, leaving as little as possible required for renderers to implement themselves.

    +

    For reference, check out the javascript interpreter or tui renderer as a starting point for your custom renderer.

    +

    Templates

    +

    Dioxus is built around the concept of Templates. Templates describe a UI tree known at compile time with dynamic parts filled at runtime. This is useful internally to make skip diffing static nodes, but it is also useful for the renderer to reuse parts of the UI tree. This can be useful for things like a list of items. Each item could contain some static parts and some dynamic parts. The renderer can use the template to create a static part of the UI once, clone it for each element in the list, and then fill in the dynamic parts.

    +

    Mutations

    +

    The Mutation type is a serialized enum that represents an operation that should be applied to update the UI. The variants roughly follow this set:

    +
    
    +#![allow(unused)]
    +fn main() {
    +enum Mutation {
    +    AppendChildren,
    +    AssignId,
    +    CreatePlaceholder,
    +    CreateTextNode,
    +    HydrateText,
    +    LoadTemplate,
    +    ReplaceWith,
    +    ReplacePlaceholder,
    +    InsertAfter,
    +    InsertBefore,
    +    SetAttribute,
    +    SetText,
    +    NewEventListener,
    +    RemoveEventListener,
    +    Remove,
    +    PushRoot,
    +}
    +}
    +
    +

    The Dioxus diffing mechanism operates as a stack machine where the LoadTemplate, CreatePlaceholder, and CreateTextNode mutations pushes a new "real" DOM node onto the stack and AppendChildren, InsertAfter, InsertBefore, ReplacePlaceholder, and ReplaceWith all remove nodes from the stack.

    +

    Node storage

    +

    Dioxus saves and loads elements with IDs. Inside the VirtualDOM, this is just tracked as as a u64.

    +

    Whenever a CreateElement edit is generated during diffing, Dioxus increments its node counter and assigns that new element its current NodeCount. The RealDom is responsible for remembering this ID and pushing the correct node when id is used in a mutation. Dioxus reclaims the IDs of elements when removed. To stay in sync with Dioxus you can use a sparse Vec (Vec<Option>) with possibly unoccupied items. You can use the ids as indexes into the Vec for elements, and grow the Vec when an id does not exist.

    +

    An Example

    +

    For the sake of understanding, let's consider this example – a very simple UI declaration:

    +
    
    +#![allow(unused)]
    +fn main() {
    +rsx!( h1 {"count: {x}"} )
    +}
    +
    +

    Building Templates

    +

    The above rsx will create a template that contains one static h1 tag and a placeholder for a dynamic text node. The template contains the static parts of the UI, and ids for the dynamic parts along with the paths to access them.

    +

    The template will look something like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +Template {
    +    // Some id that is unique for the entire project
    +    name: "main.rs:1:1:0",
    +    // The root nodes of the template
    +    roots: &[
    +        TemplateNode::Element {
    +            tag: "h1",
    +            namespace: None,
    +            attrs: &[],
    +            children: &[
    +                TemplateNode::DynamicText {
    +                    id: 0
    +                },
    +            ],
    +        }
    +    ],
    +    // the path to each of the dynamic nodes
    +    node_paths: &[
    +        // the path to dynamic node with a id of 0
    +        &[
    +            // on the first root node
    +            0,
    +            // the first child of the root node
    +            0,
    +        ]
    +    ],
    +    // the path to each of the dynamic attributes
    +    attr_paths: &'a [&'a [u8]],
    +}
    +}
    +
    +
    +

    For more detailed docs about the struture of templates see the Template api docs

    +
    +

    This template will be sent to the renderer in the list of templates supplied with the mutations the first time it is used. Any time the renderer encounters a LoadTemplate mutation after this, it should clone the template and store it in the given id.

    +

    For dynamic nodes and dynamic text nodes, a placeholder node should be created and inserted into the UI so that the node can be modified later.

    +

    In HTML renderers, this template could look like this:

    +
    <h1>""</h1>
    +
    +

    Applying Mutations

    +

    After the renderer has created all of the new templates, it can begin to process the mutations.

    +

    When the renderer starts, it should contain the Root node on the stack and store the Root node with an id of 0. The Root node is the top-level node of the UI. In HTML, this is the <div id="main"> element.

    +
    
    +#![allow(unused)]
    +fn main() {
    +instructions: []
    +stack: [
    +    RootNode,
    +]
    +nodes: [
    +    RootNode,
    +]
    +}
    +
    +

    The first mutation is a LoadTemplate mutation. This tells the renderer to load a root from the template with the given id. The renderer will then push the root node of the template onto the stack and store it with an id for later. In this case, the root node is an h1 element.

    +
    
    +#![allow(unused)]
    +fn main() {
    +instructions: [
    +    LoadTemplate {
    +        // the id of the template
    +        name: "main.rs:1:1:0",
    +        // the index of the root node in the template
    +        index: 0,
    +        // the id to store
    +        id: ElementId(1),
    +    }
    +]
    +stack: [
    +    RootNode,
    +    <h1>""</h1>,
    +]
    +nodes: [
    +    RootNode,
    +    <h1>""</h1>,
    +]
    +}
    +
    +

    Next, Dioxus will create the dynamic text node. The diff algorithm decides that this node needs to be created, so Dioxus will generate the Mutation HydrateText. When the renderer receives this instruction, it will navigate to the placeholder text node in the template and replace it with the new text.

    +
    
    +#![allow(unused)]
    +fn main() {
    +instructions: [
    +    LoadTemplate {
    +        name: "main.rs:1:1:0",
    +        index: 0,
    +        id: ElementId(1),
    +    },
    +    HydrateText {
    +        // the id to store the text node
    +        id: ElementId(2),
    +        // the text to set
    +        text: "count: 0",
    +    }
    +]
    +stack: [
    +    RootNode,
    +    <h1>"count: 0"</h1>,
    +]
    +nodes: [
    +    RootNode,
    +    <h1>"count: 0"</h1>,
    +    "count: 0",
    +]
    +}
    +
    +

    Remember, the h1 node is not attached to anything (it is unmounted) so Dioxus needs to generate an Edit that connects the h1 node to the Root. It depends on the situation, but in this case, we use AppendChildren. This pops the text node off the stack, leaving the Root element as the next element on the stack.

    +
    
    +#![allow(unused)]
    +fn main() {
    +instructions: [
    +    LoadTemplate {
    +        name: "main.rs:1:1:0",
    +        index: 0,
    +        id: ElementId(1),
    +    },
    +    HydrateText {
    +        id: ElementId(2),
    +        text: "count: 0",
    +    },
    +    AppendChildren {
    +        // the id of the parent node
    +        id: ElementId(0),
    +        // the number of nodes to pop off the stack and append
    +        m: 1
    +    }
    +]
    +stack: [
    +    RootNode,
    +]
    +nodes: [
    +    RootNode,
    +    <h1>"count: 0"</h1>,
    +    "count: 0",
    +]
    +}
    +
    +

    Over time, our stack looked like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +[Root]
    +[Root, <h1>""</h1>]
    +[Root, <h1>"count: 0"</h1>]
    +[Root]
    +}
    +
    +

    Conveniently, this approach completely separates the Virtual DOM and the Real DOM. Additionally, these edits are serializable, meaning we can even manage UIs across a network connection. This little stack machine and serialized edits make Dioxus independent of platform specifics.

    +

    Dioxus is also really fast. Because Dioxus splits the diff and patch phase, it's able to make all the edits to the RealDOM in a very short amount of time (less than a single frame) making rendering very snappy. It also allows Dioxus to cancel large diffing operations if higher priority work comes in while it's diffing.

    +

    This little demo serves to show exactly how a Renderer would need to process a mutation stream to build UIs.

    +

    Event loop

    +

    Like most GUIs, Dioxus relies on an event loop to progress the VirtualDOM. The VirtualDOM itself can produce events as well, so it's important for your custom renderer can handle those too.

    +

    The code for the WebSys implementation is straightforward, so we'll add it here to demonstrate how simple an event loop is:

    +
    pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
    +    // Push the body element onto the WebsysDom's stack machine
    +    let mut websys_dom = crate::new::WebsysDom::new(prepare_websys_dom());
    +    websys_dom.stack.push(root_node);
    +
    +    // Rebuild or hydrate the virtualdom
    +    let mutations = self.internal_dom.rebuild();
    +    websys_dom.apply_mutations(mutations);
    +
    +    // Wait for updates from the real dom and progress the virtual dom
    +    loop {
    +        let user_input_future = websys_dom.wait_for_event();
    +        let internal_event_future = self.internal_dom.wait_for_work();
    +
    +        match select(user_input_future, internal_event_future).await {
    +            Either::Left((_, _)) => {
    +                let mutations = self.internal_dom.work_with_deadline(|| false);
    +                websys_dom.apply_mutations(mutations);
    +            },
    +            Either::Right((event, _)) => websys_dom.handle_event(event),
    +        }
    +
    +        // render
    +    }
    +}
    +
    +

    It's important to decode what the real events are for your event system into Dioxus' synthetic event system (synthetic meaning abstracted). This simply means matching your event type and creating a Dioxus UserEvent type. Right now, the virtual event system is modeled almost entirely around the HTML spec, but we are interested in slimming it down.

    +
    fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
    +    match event.type_().as_str() {
    +        "keydown" => {
    +            let event: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
    +            UserEvent::KeyboardEvent(UserEvent {
    +                scope_id: None,
    +                priority: EventPriority::Medium,
    +                name: "keydown",
    +                // This should be whatever element is focused
    +                element: Some(ElementId(0)),
    +                data: Arc::new(KeyboardData{
    +                    char_code: event.char_code(),
    +                    key: event.key(),
    +                    key_code: event.key_code(),
    +                    alt_key: event.alt_key(),
    +                    ctrl_key: event.ctrl_key(),
    +                    meta_key: event.meta_key(),
    +                    shift_key: event.shift_key(),
    +                    location: event.location(),
    +                    repeat: event.repeat(),
    +                    which: event.which(),
    +                })
    +            })
    +        }
    +        _ => todo!()
    +    }
    +}
    +
    +

    Custom raw elements

    +

    If you need to go as far as relying on custom elements/attributes for your renderer – you totally can. This still enables you to use Dioxus' reactive nature, component system, shared state, and other features, but will ultimately generate different nodes. All attributes and listeners for the HTML and SVG namespace are shuttled through helper structs that essentially compile away. You can drop in your elements any time you want, with little hassle. However, you must be sure your renderer can handle the new namespace.

    +

    For more examples and information on how to create custom namespaces, see the dioxus_html crate.

    +

    Native Core

    +

    If you are creating a renderer in rust, the native-core crate provides some utilities to implement a renderer. It provides an abstraction over Mutations and Templates and contains helpers that can handle the layout and text editing for you.

    +

    The RealDom

    +

    The RealDom is a higher-level abstraction over updating the Dom. It uses an entity component system to manage the state of nodes. This system allows you to modify insert and modify arbitrary components on nodes. On top of this, the RealDom provides a way to manage a tree of nodes, and the State trait provides a way to automatically add and update these components when the tree is modified. It also provides a way to apply Mutations to the RealDom.

    +

    Example

    +

    Let's build a toy renderer with borders, size, and text color. +Before we start let's take a look at an example element we can render:

    +
    
    +#![allow(unused)]
    +fn main() {
    +cx.render(rsx!{
    +    div{
    +        color: "red",
    +        p{
    +            border: "1px solid black",
    +            "hello world"
    +        }
    +    }
    +})
    +}
    +
    +

    In this tree, the color depends on the parent's color. The layout depends on the children's layout, the current text, and the text size. The border depends on only the current node.

    +

    In the following diagram arrows represent dataflow:

    +

    +

    To help in building a Dom, native-core provides the State trait and a RealDom struct. The State trait provides a way to describe how states in a node depend on other states in its relatives. By describing how to update a single node from its relations, native-core will derive a way to update the states of all nodes for you. Once you have a state you can provide it as a generic to RealDom. RealDom provides all of the methods to interact and update your new dom.

    +

    Native Core cannot create all of the required methods for the State trait, but it can derive some of them. To implement the State trait, you must implement the following methods and let the #[partial_derive_state] macro handle the rest:

    +
    // All states must derive Component (https://docs.rs/shipyard/latest/shipyard/derive.Component.html)
    +// They also must implement Default or provide a custom implementation of create in the State trait
    +#[derive(Default, Component)]
    +struct MyState;
    +
    +/// Derive some of the boilerplate for the State implementation
    +#[partial_derive_state]
    +impl State for MyState {
    +    // The states of the parent nodes this state depends on
    +    type ParentDependencies = ();
    +
    +    // The states of the child nodes this state depends on
    +    type ChildDependencies = (Self,);
    +
    +    // The states of the current node this state depends on
    +    type NodeDependencies = ();
    +
    +    // The parts of the current text, element, or placeholder node in the tree that this state depends on
    +    const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new();
    +
    +    // How to update the state of the current node based on the state of the parent nodes, child nodes, and the current node
    +    // Returns true if the node was updated and false if the node was not updated
    +    fn update<'a>(
    +        &mut self,
    +        // The view of the current node limited to the parts this state depends on
    +        _node_view: NodeView<()>,
    +        // The state of the current node that this state depends on
    +        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
    +        // The state of the parent nodes that this state depends on
    +        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        // The state of the child nodes that this state depends on
    +        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        // The context of the current node used to pass global state into the tree
    +        _context: &SendAnyMap,
    +    ) -> bool {
    +        todo!()
    +    }
    +
    +    // partial_derive_state will generate a default implementation of all the other methods
    +}
    +
    +

    Lets take a look at how to implement the State trait for a simple renderer.

    +
    
    +#![allow(unused)]
    +fn main() {
    +struct FontSize(f64);
    +
    +// All states need to derive Component
    +#[derive(Default, Debug, Copy, Clone, Component)]
    +struct Size(f64, f64);
    +
    +/// Derive some of the boilerplate for the State implementation
    +#[partial_derive_state]
    +impl State for Size {
    +    type ParentDependencies = ();
    +
    +    // The size of the current node depends on the size of its children
    +    type ChildDependencies = (Self,);
    +
    +    type NodeDependencies = ();
    +
    +    // Size only cares about the width, height, and text parts of the current node
    +    const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
    +        // Get access to the width and height attributes
    +        .with_attrs(AttributeMaskBuilder::Some(&["width", "height"]))
    +        // Get access to the text of the node
    +        .with_text();
    +
    +    fn update<'a>(
    +        &mut self,
    +        node_view: NodeView<()>,
    +        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
    +        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        context: &SendAnyMap,
    +    ) -> bool {
    +        let font_size = context.get::<FontSize>().unwrap().0;
    +        let mut width;
    +        let mut height;
    +        if let Some(text) = node_view.text() {
    +            // if the node has text, use the text to size our object
    +            width = text.len() as f64 * font_size;
    +            height = font_size;
    +        } else {
    +            // otherwise, the size is the maximum size of the children
    +            width = children
    +                .iter()
    +                .map(|(item,)| item.0)
    +                .reduce(|accum, item| if accum >= item { accum } else { item })
    +                .unwrap_or(0.0);
    +
    +            height = children
    +                .iter()
    +                .map(|(item,)| item.1)
    +                .reduce(|accum, item| if accum >= item { accum } else { item })
    +                .unwrap_or(0.0);
    +        }
    +        // if the node contains a width or height attribute it overrides the other size
    +        for a in node_view.attributes().into_iter().flatten() {
    +            match &*a.attribute.name {
    +                "width" => width = a.value.as_float().unwrap(),
    +                "height" => height = a.value.as_float().unwrap(),
    +                // because Size only depends on the width and height, no other attributes will be passed to the member
    +                _ => panic!(),
    +            }
    +        }
    +        // to determine what other parts of the dom need to be updated we return a boolean that marks if this member changed
    +        let changed = (width != self.0) || (height != self.1);
    +        *self = Self(width, height);
    +        changed
    +    }
    +}
    +
    +#[derive(Debug, Clone, Copy, PartialEq, Default, Component)]
    +struct TextColor {
    +    r: u8,
    +    g: u8,
    +    b: u8,
    +}
    +
    +#[partial_derive_state]
    +impl State for TextColor {
    +    // TextColor depends on the TextColor part of the parent
    +    type ParentDependencies = (Self,);
    +
    +    type ChildDependencies = ();
    +
    +    type NodeDependencies = ();
    +
    +    // TextColor only cares about the color attribute of the current node
    +    const NODE_MASK: NodeMaskBuilder<'static> =
    +        // Get access to the color attribute
    +        NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["color"]));
    +
    +    fn update<'a>(
    +        &mut self,
    +        node_view: NodeView<()>,
    +        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
    +        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        _context: &SendAnyMap,
    +    ) -> bool {
    +        // TextColor only depends on the color tag, so getting the first tag is equivilent to looking through all tags
    +        let new = match node_view
    +            .attributes()
    +            .and_then(|mut attrs| attrs.next())
    +            .and_then(|attr| attr.value.as_text())
    +        {
    +            // if there is a color tag, translate it
    +            Some("red") => TextColor { r: 255, g: 0, b: 0 },
    +            Some("green") => TextColor { r: 0, g: 255, b: 0 },
    +            Some("blue") => TextColor { r: 0, g: 0, b: 255 },
    +            Some(color) => panic!("unknown color {color}"),
    +            // otherwise check if the node has a parent and inherit that color
    +            None => match parent {
    +                Some((parent,)) => *parent,
    +                None => Self::default(),
    +            },
    +        };
    +        // check if the member has changed
    +        let changed = new != *self;
    +        *self = new;
    +        changed
    +    }
    +}
    +
    +#[derive(Debug, Clone, Copy, PartialEq, Default, Component)]
    +struct Border(bool);
    +
    +#[partial_derive_state]
    +impl State for Border {
    +    // TextColor depends on the TextColor part of the parent
    +    type ParentDependencies = (Self,);
    +
    +    type ChildDependencies = ();
    +
    +    type NodeDependencies = ();
    +
    +    // Border does not depended on any other member in the current node
    +    const NODE_MASK: NodeMaskBuilder<'static> =
    +        // Get access to the border attribute
    +        NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["border"]));
    +
    +    fn update<'a>(
    +        &mut self,
    +        node_view: NodeView<()>,
    +        _node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
    +        _parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        _children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
    +        _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(),
    +        );
    +        // check if the member has changed
    +        let changed = new != *self;
    +        *self = new;
    +        changed
    +    }
    +}
    +}
    +
    +

    Now that we have our state, we can put it to use in our RealDom. We can update the RealDom with apply_mutations to update the structure of the dom (adding, removing, and changing properties of nodes) and then update_state to update the States for each of the nodes that changed.

    +
    fn main() -> Result<(), Box<dyn std::error::Error>> {
    +    fn app(cx: Scope) -> Element {
    +        let count = use_state(cx, || 0);
    +
    +        use_future(cx, (count,), |(count,)| async move {
    +            loop {
    +                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    +                count.set(*count + 1);
    +            }
    +        });
    +
    +        cx.render(rsx! {
    +            div{
    +                color: "red",
    +                "{count}"
    +            }
    +        })
    +    }
    +
    +    // create the vdom, the real_dom, and the binding layer between them
    +    let mut vdom = VirtualDom::new(app);
    +    let mut rdom: RealDom = RealDom::new([
    +        Border::to_type_erased(),
    +        TextColor::to_type_erased(),
    +        Size::to_type_erased(),
    +    ]);
    +    let mut dioxus_intigration_state = DioxusState::create(&mut rdom);
    +
    +    let mutations = vdom.rebuild();
    +    // update the structure of the real_dom tree
    +    dioxus_intigration_state.apply_mutations(&mut rdom, mutations);
    +    let mut ctx = SendAnyMap::new();
    +    // set the font size to 3.3
    +    ctx.insert(FontSize(3.3));
    +    // update the State for nodes in the real_dom tree
    +    let _to_rerender = rdom.update_state(ctx);
    +
    +    // we need to run the vdom in a async runtime
    +    tokio::runtime::Builder::new_current_thread()
    +        .enable_all()
    +        .build()?
    +        .block_on(async {
    +            loop {
    +                // wait for the vdom to update
    +                vdom.wait_for_work().await;
    +
    +                // get the mutations from the vdom
    +                let mutations = vdom.render_immediate();
    +
    +                // update the structure of the real_dom tree
    +                dioxus_intigration_state.apply_mutations(&mut rdom, mutations);
    +
    +                // update the state of the real_dom tree
    +                let mut ctx = SendAnyMap::new();
    +                // set the font size to 3.3
    +                ctx.insert(FontSize(3.3));
    +                let _to_rerender = rdom.update_state(ctx);
    +
    +                // render...
    +                rdom.traverse_depth_first(|node| {
    +                    let indent = " ".repeat(node.height() as usize);
    +                    let color = *node.get::<TextColor>().unwrap();
    +                    let size = *node.get::<Size>().unwrap();
    +                    let border = *node.get::<Border>().unwrap();
    +                    let id = node.id();
    +                    let node = node.node_type();
    +                    let node_type = &*node;
    +                    println!("{indent}{id:?} {color:?} {size:?} {border:?} {node_type:?}");
    +                });
    +            }
    +        })
    +}
    +
    +

    Layout

    +

    For most platforms, the layout of the Elements will stay the same. The layout_attributes module provides a way to apply HTML attributes a Taffy layout style.

    +

    Text Editing

    +

    To make it easier to implement text editing in rust renderers, native-core also contains a renderer-agnostic cursor system. The cursor can handle text editing, selection, and movement with common keyboard shortcuts integrated.

    +
    
    +#![allow(unused)]
    +fn main() {
    +fn text_editing() {
    +    let mut cursor = Cursor::default();
    +    let mut text = String::new();
    +
    +    // handle keyboard input with a max text length of 10
    +    cursor.handle_input(
    +        &Code::ArrowRight,
    +        &Key::ArrowRight,
    +        &Modifiers::empty(),
    +        &mut text,
    +        10,
    +    );
    +
    +    // mannually select text between characters 0-5 on the first line (this could be from dragging with a mouse)
    +    cursor.start = Pos::new(0, 0);
    +    cursor.end = Some(Pos::new(5, 0));
    +
    +    // delete the selected text and move the cursor to the start of the selection
    +    cursor.delete_selection(&mut text);
    +}
    +}
    +
    +

    Conclusion

    +

    That should be it! You should have nearly all the knowledge required on how to implement your renderer. We're super interested in seeing Dioxus apps brought to custom desktop renderers, mobile renderers, video game UI, and even augmented reality! If you're interested in contributing to any of these projects, don't be afraid to reach out or join the community.

    +

    Contributing

    +

    Development happens in the Dioxus GitHub repository. If you've found a bug or have an idea for a feature, please submit an issue (but first check if someone hasn't done it already).

    +

    GitHub discussions can be used as a place to ask for help or talk about features. You can also join our Discord channel where some development discussion happens.

    +

    Improving Docs

    +

    If you'd like to improve the docs, PRs are welcome! Both Rust docs (source) and this guide (source) can be found in the GitHub repo.

    +

    Working on the Ecosystem

    +

    Part of what makes React great is the rich ecosystem. We'd like the same for Dioxus! So if you have a library in mind that you'd like to write and many people would benefit from, it will be appreciated. You can browse npm.js for inspiration. Once you are done, add your library to the awesome dioxus list or share it in the #I-made-a-thing channel on Discord.

    +

    Bugs & Features

    +

    If you've fixed an open issue, feel free to submit a PR! You can also take a look at the roadmap and work on something in there. Consider reaching out to the team first to make sure everyone's on the same page, and you don't do useless work!

    +

    All pull requests (including those made by a team member) must be approved by at least one other team member. +Larger, more nuanced decisions about design, architecture, breaking changes, trade-offs, etc. are made by team consensus.

    +

    Tools

    +

    The following tools can be helpful when developing Dioxus. Many of these tools are used in the CI pipeline. Running them locally before submitting a PR instead of waiting for CI can save time.

    + +
    cargo fmt --all
    +
    +
      +
    • All code is formatted with rustfmt
    • +
    +
    cargo check --workspace --examples --tests
    +
    +
      +
    • All code is linted with Clippy
    • +
    +
    cargo clippy --workspace --examples --tests -- -D warnings
    +
    +
      +
    • Crates that use unsafe are checked for undefined behavior with MIRI. MIRI can be helpful to debug what unsafe code is causing issues. Only code that does not interact with system calls can be checked with MIRI. Currently, this is used for the two MIRI tests in dioxus-core and dioxus-native-core.
    • +
    +
    cargo miri test --package dioxus-core --test miri_stress
    +cargo miri test --package dioxus-native-core --test miri_native
    +
    +
      +
    • Rust analyzer can be very helpful for quick feedback in your IDE.
    • +
    +

    Project Struture

    +

    There are many packages in the Dioxus organization. This document will help you understand the purpose of each package and how they fit together.

    +

    Renderers

    +
      +
    • Desktop: A Render that Runs Dioxus applications natively, but renders them with the system webview
    • +
    • Mobile: A Render that Runs Dioxus applications natively, but renders them with the system webview. This is currently a copy of the desktop render
    • +
    • Web: Renders Dioxus applications in the browser by compiling to WASM and manipulating the DOM
    • +
    • Liveview: A Render that Runs on the server, and renders using a websocket proxy in the browser
    • +
    • Rink: A Renderer that renders a HTML-like tree into a terminal
    • +
    • TUI: A Renderer that uses Rink to render a Dioxus application in a terminal
    • +
    • Blitz-Core: An experimental native renderer that renders a HTML-like tree using WGPU.
    • +
    • Blitz: An experimental native renderer that uses Blitz-Core to render a Dioxus application using WGPU.
    • +
    • SSR: A Render that Runs Dioxus applications on the server, and renders them to HTML
    • +
    +

    State Management/Hooks

    +
      +
    • Hooks: A collection of common hooks for Dioxus applications
    • +
    • Signals: A experimental state management library for Dioxus applications. This currently contains a Copy version of UseRef
    • +
    • Dioxus STD: A collection of platform agnostic hooks to interact with system interfaces (The clipboard, camera, etc.).
    • +
    • Fermi: A global state management library for Dioxus applications. +Router: A client-side router for Dioxus applications
    • +
    +

    Core utilities

    +
      +
    • core: The core virtual dom implementation every Dioxus application uses + +
    • +
    • RSX: The core parsing for RSX used for hot reloading, autoformatting, and the macro
    • +
    • core-macro: The rsx! macro used to write Dioxus applications. (This is a wrapper over the RSX crate)
    • +
    • HTML macro: A html-like alternative to the RSX macro
    • +
    +

    Native Renderer Utilities

    + +

    Web renderer tooling

    +
      +
    • HTML: defines html specific elements, events, and attributes
    • +
    • Interpreter: defines browser bindings used by the web and desktop renderers
    • +
    +

    Developer tooling

    +
      +
    • hot-reload: Macro that uses the RSX crate to hot reload static parts of any rsx! macro. This macro works with any non-web renderer with an integration
    • +
    • autofmt: Formats RSX code
    • +
    • rsx-rosetta: Handles conversion between HTML and RSX
    • +
    • CLI: A Command Line Interface and VSCode extension to assist with Dioxus usage
    • +
    +

    Walkthrough of the Hello World Example Internals

    +

    This walkthrough will take you through the internals of the Hello World example program. It will explain how major parts of Dioxus internals interact with each other to take the readme example from a source file to a running application. This guide should serve as a high-level overview of the internals of Dioxus. It is not meant to be a comprehensive guide.

    +

    The Source File

    +

    We start will a hello world program. This program renders a desktop app with the text "Hello World" in a webview.

    +
    //! Example: README.md showcase
    +//!
    +//! The example from the README.md.
    +
    +use dioxus::prelude::*;
    +
    +fn main() {
    +    dioxus_desktop::launch(app);
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(rsx! {
    +        h1 { "High-Five counter: {count}" }
    +        button { onclick: move |_| count += 1, "Up high!" }
    +        button { onclick: move |_| count -= 1, "Down low!" }
    +    })
    +}
    +
    +

    +

    The rsx! Macro

    +

    Before the Rust compiler runs the program, it will expand all macros. Here is what the hello world example looks like expanded:

    +
    use dioxus::prelude::*;
    +
    +fn main() {
    +    dioxus_desktop::launch(app);
    +}
    +
    +fn app(cx: Scope) -> Element {
    +    let mut count = use_state(cx, || 0);
    +
    +    cx.render(
    +        // rsx expands to LazyNodes::new
    +        ::dioxus::core::LazyNodes::new(
    +            move |__cx: &::dioxus::core::ScopeState| -> ::dioxus::core::VNode {
    +                // The template is every static part of the rsx
    +                static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
    +                    // This is the source location of the rsx that generated this template. This is used to make hot rsx reloading work. Hot rsx reloading just replaces the template with a new one generated from the rsx by the CLI.
    +                    name: "examples\\readme.rs:14:15:250",
    +                    // The root nodes are the top level nodes of the rsx
    +                    roots: &[
    +                        // The h1 node
    +                        ::dioxus::core::TemplateNode::Element {
    +                            // Find the built in h1 tag in the dioxus_elements crate exported by the dioxus html crate
    +                            tag: dioxus_elements::h1::TAG_NAME,
    +                            namespace: dioxus_elements::h1::NAME_SPACE,
    +                            attrs: &[],
    +                            // The children of the h1 node
    +                            children: &[
    +                                // The dynamic count text node
    +                                // Any nodes that are dynamic have a dynamic placeholder with a unique index
    +                                ::dioxus::core::TemplateNode::DynamicText {
    +                                    // This index is used to find what element in `dynamic_nodes` to use instead of the placeholder
    +                                    id: 0usize,
    +                                },
    +                            ],
    +                        },
    +                        // The up high button node
    +                        ::dioxus::core::TemplateNode::Element {
    +                            tag: dioxus_elements::button::TAG_NAME,
    +                            namespace: dioxus_elements::button::NAME_SPACE,
    +                            attrs: &[
    +                                // The dynamic onclick listener attribute
    +                                // Any attributes that are dynamic have a dynamic placeholder with a unique index.
    +                                ::dioxus::core::TemplateAttribute::Dynamic {
    +                                    // Similar to dynamic nodes, dynamic attributes have a unique index used to find the attribute in `dynamic_attrs` to use instead of the placeholder
    +                                    id: 0usize,
    +                                },
    +                            ],
    +                            children: &[::dioxus::core::TemplateNode::Text { text: "Up high!" }],
    +                        },
    +                        // The down low button node
    +                        ::dioxus::core::TemplateNode::Element {
    +                            tag: dioxus_elements::button::TAG_NAME,
    +                            namespace: dioxus_elements::button::NAME_SPACE,
    +                            attrs: &[
    +                                // The dynamic onclick listener attribute
    +                                ::dioxus::core::TemplateAttribute::Dynamic { id: 1usize },
    +                            ],
    +                            children: &[::dioxus::core::TemplateNode::Text { text: "Down low!" }],
    +                        },
    +                    ],
    +                    // Node paths is a list of paths to every dynamic node in the rsx
    +                    node_paths: &[
    +                        // The first node path is the path to the dynamic node with an id of 0 (the count text node)
    +                        &[
    +                            // Go to the index 0 root node
    +                            0u8,
    +                            //
    +                            // Go to the first child of the root node
    +                            0u8,
    +                        ],
    +                    ],
    +                    // Attr paths is a list of paths to every dynamic attribute in the rsx
    +                    attr_paths: &[
    +                        // The first attr path is the path to the dynamic attribute with an id of 0 (the up high button onclick listener)
    +                        &[
    +                            // Go to the index 1 root node
    +                            1u8,
    +                        ],
    +                        // The second attr path is the path to the dynamic attribute with an id of 1 (the down low button onclick listener)
    +                        &[
    +                            // Go to the index 2 root node
    +                            2u8,
    +                        ],
    +                    ],
    +                };
    +                // The VNode is a reference to the template with the dynamic parts of the rsx
    +                ::dioxus::core::VNode {
    +                    parent: None,
    +                    key: None,
    +                    // The static template this node will use. The template is stored in a Cell so it can be replaced with a new template when hot rsx reloading is enabled
    +                    template: std::cell::Cell::new(TEMPLATE),
    +                    root_ids: Default::default(),
    +                    dynamic_nodes: __cx.bump().alloc([
    +                        // The dynamic count text node (dynamic node id 0)
    +                        __cx.text_node(format_args!("High-Five counter: {0}", count)),
    +                    ]),
    +                    dynamic_attrs: __cx.bump().alloc([
    +                        // The dynamic up high button onclick listener (dynamic attribute id 0)
    +                        dioxus_elements::events::onclick(__cx, move |_| count += 1),
    +                        // The dynamic down low button onclick listener (dynamic attribute id 1)
    +                        dioxus_elements::events::onclick(__cx, move |_| count -= 1),
    +                    ]),
    +                }
    +            },
    +        ),
    +    )
    +}
    +
    +

    The rsx macro separates the static parts of the rsx (the template) and the dynamic parts (the dynamic_nodes and dynamic_attributes).

    +

    The static template only contains the parts of the rsx that cannot change at runtime with holes for the dynamic parts:

    +

    +

    The dynamic_nodes and dynamic_attributes are the parts of the rsx that can change at runtime:

    +

    +

    Launching the App

    +

    The app is launched by calling the launch function with the root component. Internally, this function will create a new web view using wry and create a virtual dom with the root component. This guide will not explain the renderer in-depth, but you can read more about it in the custom renderer section.

    +

    The Virtual DOM

    +

    Before we dive into the initial render in the virtual dom, we need to discuss what the virtual dom is. The virtual dom is a representation of the dom that is used to diff the current dom from the new dom. This diff is then used to create a list of mutations that need to be applied to the dom.

    +

    The Virtual Dom roughly looks like this:

    +
    
    +#![allow(unused)]
    +fn main() {
    +pub struct VirtualDom {
    +    // All the templates that have been created or set durring hot reloading
    +    pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>,
    +
    +    // A slab of all the scopes that have been created
    +    pub(crate) scopes: ScopeSlab,
    +
    +    // All scopes that have been marked as dirty
    +    pub(crate) dirty_scopes: BTreeSet<DirtyScope>,
    +
    +    // Every element is actually a dual reference - one to the template and the other to the dynamic node in that template
    +    pub(crate) elements: Slab<ElementRef>,
    +
    +    // This receiver is used to receive messages from hooks about what scopes need to be marked as dirty
    +    pub(crate) rx: futures_channel::mpsc::UnboundedReceiver<SchedulerMsg>,
    +
    +    // The changes queued up to be sent to the renderer
    +    pub(crate) mutations: Mutations<'static>,
    +}
    +}
    +
    +
    +

    What is a slab? +A slab acts like a hashmap with integer keys if you don't care about the value of the keys. It is internally backed by a dense vector which makes it more efficient than a hashmap. When you insert a value into a slab, it returns an integer key that you can use to retrieve the value later.

    +
    +
    +

    How does Dioxus use slabs? +Dioxus uses "synchronized slabs" to communicate between the renderer and the VDOM. When an node is created in the Virtual Dom, a ElementId is passed along with the mutation to the renderer to identify the node. These ids are used by the Virtual Dom to reference that nodes in future mutations like setting an attribute on a node or removing a node. +When the renderer sends an event to the Virtual Dom, it sends the ElementId of the node that the event was triggered on. The Virtual Dom uses this id to find the node in the slab and then run the necessary event handlers.

    +
    +

    The virtual dom is a tree of scopes. A new scope is created for every component when it is first rendered and recycled when the component is unmounted.

    +

    Scopes serve three main purposes:

    +
      +
    1. They store the state of hooks used by the component
    2. +
    3. They store the state for the context API
    4. +
    5. They store the current and previous VNode that was rendered for diffing
    6. +
    +

    The Initial Render

    +

    The root scope is created and rebuilt:

    +
      +
    1. The root component is run
    2. +
    3. The root component returns a VNode
    4. +
    5. Mutations for the VNode are created and added to the mutation list (this may involve creating new child components)
    6. +
    7. The VNode is stored in the root scope
    8. +
    +

    After the root scope is built, the mutations are sent to the renderer to be applied to the dom.

    +

    After the initial render, the root scope looks like this:

    +

    +

    Waiting for Events

    +

    The Virtual Dom will only ever rerender a scope if it is marked as dirty. Each hook is responsible for marking the scope as dirty if the state has changed. Hooks can mark a scope as dirty by sending a message to the Virtual Dom's channel.

    +

    There are generally two ways a scope is marked as dirty:

    +
      +
    1. The renderer triggers an event: This causes an event listener to be called if needed which may mark a component as dirty
    2. +
    3. The renderer calls wait for work: This polls futures which may mark a component as dirty
    4. +
    +

    Once at least one scope is marked as dirty, the renderer can call render_with_deadline to diff the dirty scopes.

    +

    Diffing Scopes

    +

    If the user clicked the "up high" button, the root scope would be marked as dirty by the use_state hook. Once the desktop renderer calls render_with_deadline, the root scope would be diffed.

    +

    To start the diffing process, the component is run. After the root component is run it will look like this:

    +

    +

    Next, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.

    +

    When a component is re-rendered, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.

    +

    The diffing algorithm goes through the list of dynamic attributes and nodes and compares them to the previous VNode. If the attribute or node has changed, a mutation that describes the change is added to the mutation list.

    +

    Here is what the diffing algorithm looks like for the root scope (red lines indicate that a mutation was generated, and green lines indicate that no mutation was generated)

    +

    +

    Conclusion

    +

    This is only a brief overview of how the Virtual Dom works. There are several aspects not yet covered in this guide including how the Virtual Dom handles async-components, keyed diffing, and how it uses bump allocation to efficiently allocate VNodes. If need more information about the Virtual Dom, you can read the code of the core crate or reach out to us on Discord.

    +

    Overall Goals

    +

    This document outlines some of the overall goals for Dioxus. These goals are not set in stone, but they represent general guidelines for the project.

    +

    The goal of Dioxus is to make it easy to build cross-platform applications that scale.

    +

    Cross-Platform

    +

    Dioxus is designed to be cross-platform by default. This means that it should be easy to build applications that run on the web, desktop, and mobile. However, Dioxus should also be flexible enough to allow users to opt into platform-specific features when needed. The use_eval is one example of this. By default, Dioxus does not assume that the platform supports JavaScript, but it does provide a hook that allows users to opt into JavaScript when needed.

    +

    Performance

    +

    As Dioxus applications grow, they should remain relatively performant without the need for manual optimizations. There will be cases where manual optimizations are needed, but Dioxus should try to make these cases as rare as possible.

    +

    One of the benefits of the core architecture of Dioxus is that it delivers reasonable performance even when components are rerendered often. It is based on a Virtual Dom which performs diffing which should prevent unnecessary re-renders even when large parts of the component tree are rerun. On top of this, Dioxus groups static parts of the RSX tree together to skip diffing them entirely.

    +

    Type Safety

    +

    As teams grow, the Type safety of Rust is a huge advantage. Dioxus should leverage this advantage to make it easy to build applications with large teams.

    +

    To take full advantage of Rust's type system, Dioxus should try to avoid exposing public Any types and string-ly typed APIs where possible.

    +

    Developer Experience

    +

    Dioxus should be easy to learn and ergonomic to use.

    +
      +
    • +

      The API of Dioxus attempts to remain close to React's API where possible. This makes it easier for people to learn Dioxus if they already know React

      +
    • +
    • +

      We can avoid the tradeoff between simplicity and flexibility by providing multiple layers of API: One for the very common use case, one for low-level control

      +
        +
      • Hooks: the hooks crate has the most common use cases, but cx.hook provides a way to access the underlying persistent reference if needed.
      • +
      • The builder pattern in platform Configs: The builder pattern is used to default to the most common use case, but users can change the defaults if needed.
      • +
      +
    • +
    • +

      Documentation:

      +
        +
      • All public APIs should have rust documentation
      • +
      • Examples should be provided for all public features. These examples both serve as documentation and testing. They are checked by CI to ensure that they continue to compile
      • +
      • The most common workflows should be documented in the guide
      • +
      +
    • +
    +

    Roadmap & Feature-set

    +

    This feature set and roadmap can help you decide if what Dioxus can do today works for you.

    +

    If a feature that you need doesn't exist or you want to contribute to projects on the roadmap, feel free to get involved by joining the discord.

    +

    Generally, here's the status of each platform:

    +
      +
    • +

      Web: Dioxus is a great choice for pure web-apps – especially for CRUD/complex apps. However, it does lack the ecosystem of React, so you might be missing a component library or some useful hook.

      +
    • +
    • +

      SSR: Dioxus is a great choice for pre-rendering, hydration, and rendering HTML on a web endpoint. Be warned – the VirtualDom is not (currently) Send + Sync.

      +
    • +
    • +

      Desktop: You can build very competent single-window desktop apps right now. However, multi-window apps require support from Dioxus core and are not ready.

      +
    • +
    • +

      Mobile: Mobile support is very young. You'll be figuring things out as you go and there are not many support crates for peripherals.

      +
    • +
    • +

      LiveView: LiveView support is very young. You'll be figuring things out as you go. Thankfully, none of it is too hard and any work can be upstreamed into Dioxus.

      +
    • +
    +

    Features

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FeatureStatusDescription
    Conditional Rendering✅if/then to hide/show component
    Map, Iterator✅map/filter/reduce to produce rsx!
    Keyed Components✅advanced diffing with keys
    Web✅renderer for web browser
    Desktop (webview)✅renderer for desktop
    Shared State (Context)✅share state through the tree
    Hooks✅memory cells in components
    SSR✅render directly to string
    Component Children✅cx.children() as a list of nodes
    Headless components✅components that don't return real elements
    Fragments✅multiple elements without a real root
    Manual Props✅Manually pass in props with spread syntax
    Controlled Inputs✅stateful wrappers around inputs
    CSS/Inline Styles✅syntax for inline styles/attribute groups
    Custom elements✅Define new element primitives
    Suspense✅schedule future render from future/promise
    Integrated error handling✅Gracefully handle errors with ? syntax
    NodeRef✅gain direct access to nodes
    Re-hydration✅Pre-render to HTML to speed up first contentful paint
    Jank-Free Rendering✅Large diffs are segmented across frames for silky-smooth transitions
    Effects✅Run effects after a component has been committed to render
    Portals🛠Render nodes outside of the traditional tree structure
    Cooperative Scheduling🛠Prioritize important events over non-important events
    Server Components🛠Hybrid components for SPA and Server
    Bundle Splitting👀Efficiently and asynchronously load the app
    Lazy Components👀Dynamically load the new components as the page is loaded
    1st class global state✅redux/recoil/mobx on top of context
    Runs natively✅runs as a portable binary w/o a runtime (Node)
    Subtree Memoization✅skip diffing static element subtrees
    High-efficiency templates✅rsx! calls are translated to templates on the DOM's side
    Compile-time correct✅Throw errors on invalid template layouts
    Heuristic Engine✅track component memory usage to minimize future allocations
    Fine-grained reactivity👀Skip diffing for fine-grain updates
    +
      +
    • ✅ = implemented and working
    • +
    • 🛠 = actively being worked on
    • +
    • 👀 = not yet implemented or being worked on
    • +
    +

    Roadmap

    +

    These Features are planned for the future of Dioxus:

    +

    Core

    +
      +
    • +Release of Dioxus Core
    • +
    • +Upgrade documentation to include more theory and be more comprehensive
    • +
    • +Support for HTML-side templates for lightning-fast dom manipulation
    • +
    • +Support for multiple renderers for same virtualdom (subtrees)
    • +
    • +Support for ThreadSafe (Send + Sync)
    • +
    • +Support for Portals
    • +
    +

    SSR

    +
      +
    • +SSR Support + Hydration
    • +
    • +Integrated suspense support for SSR
    • +
    +

    Desktop

    +
      +
    • +Declarative window management
    • +
    • +Templates for building/bundling
    • +
    • +Access to Canvas/WebGL context natively
    • +
    +

    Mobile

    +
      +
    • +Mobile standard library +
        +
      • +GPS
      • +
      • +Camera
      • +
      • +filesystem
      • +
      • +Biometrics
      • +
      • +WiFi
      • +
      • +Bluetooth
      • +
      • +Notifications
      • +
      • +Clipboard
      • +
      +
    • +
    • +Animations
    • +
    +

    Bundling (CLI)

    +
      +
    • +Translation from HTML into RSX
    • +
    • +Dev server
    • +
    • +Live reload
    • +
    • +Translation from JSX into RSX
    • +
    • +Hot module replacement
    • +
    • +Code splitting
    • +
    • +Asset macros
    • +
    • +Css pipeline
    • +
    • +Image pipeline
    • +
    +

    Essential hooks

    +
      +
    • +Router
    • +
    • +Global state management
    • +
    • +Resize observer
    • +
    +

    Work in Progress

    +

    Build Tool

    +

    We are currently working on our own build tool called Dioxus CLI which will support:

    +
      +
    • an interactive TUI
    • +
    • on-the-fly reconfiguration
    • +
    • hot CSS reloading
    • +
    • two-way data binding between browser and source code
    • +
    • an interpreter for rsx!
    • +
    • ability to publish to github/netlify/vercel
    • +
    • bundling for iOS/Desktop/etc
    • +
    +

    Server Component Support

    +

    While not currently fully implemented, the expectation is that LiveView apps can be a hybrid between Wasm and server-rendered where only portions of a page are "live" and the rest of the page is either server-rendered, statically generated, or handled by the host SPA.

    +

    Native rendering

    +

    We are currently working on a native renderer for Dioxus using WGPU called Blitz. This will allow you to build apps that are rendered natively for iOS, Android, and Desktop.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/publishing/desktop.html b/docs/nightly/guide/en/publishing/desktop.html new file mode 100644 index 000000000..1c3707617 --- /dev/null +++ b/docs/nightly/guide/en/publishing/desktop.html @@ -0,0 +1,254 @@ + + + + + + Desktop + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Publishing

    +

    Congrats! You've made your first Dioxus app that actually does some pretty cool stuff. This app uses your operating system's WebView library, so it's portable to be distributed for other platforms.

    +

    In this section, we'll cover how to bundle your app for macOS, Windows, and Linux.

    +

    Install cargo-bundle

    +

    The first thing we'll do is install cargo-bundle. This extension to cargo will make it very easy to package our app for the various platforms.

    +

    According to the cargo-bundle github page,

    +

    "cargo-bundle is a tool used to generate installers or app bundles for GUI executables built with cargo. It can create .app bundles for Mac OS X and iOS, .deb packages for Linux, and .msi installers for Windows (note however that iOS and Windows support is still experimental). Support for creating .rpm packages (for Linux) and .apk packages (for Android) is still pending."

    +

    To install, simply run

    +

    cargo install cargo-bundle

    +

    Setting up your project

    +

    To get a project setup for bundling, we need to add some flags to our Cargo.toml file.

    +
    [package]
    +name = "example"
    +# ...other fields...
    +
    +[package.metadata.bundle]
    +name = "DogSearch"
    +identifier = "com.dogs.dogsearch"
    +version = "1.0.0"
    +copyright = "Copyright (c) Jane Doe 2016. All rights reserved."
    +category = "Developer Tool"
    +short_description = "Easily search for Dog photos"
    +long_description = """
    +This app makes it quick and easy to browse photos of dogs from over 200 bree
    +"""
    +
    +

    Building

    +

    Following cargo-bundle's instructions, we simply cargo-bundle --release to produce a final app with all the optimizations and assets builtin.

    +

    Once you've ran cargo-bundle --release, your app should be accessible in

    +

    target/release/bundle/<platform>/.

    +

    For example, a macOS app would look like this:

    +

    Published App

    +

    Nice! And it's only 4.8 Mb – extremely lean!! Because Dioxus leverages your platform's native WebView, Dioxus apps are extremely memory efficient and won't waste your battery.

    +
    +

    Note: not all CSS works the same on all platforms. Make sure to view your app's CSS on each platform – or web browser (Firefox, Chrome, Safari) before publishing.

    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/publishing/index.html b/docs/nightly/guide/en/publishing/index.html new file mode 100644 index 000000000..92c09a72a --- /dev/null +++ b/docs/nightly/guide/en/publishing/index.html @@ -0,0 +1,219 @@ + + + + + + Publishing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Publishing

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/publishing/web.html b/docs/nightly/guide/en/publishing/web.html new file mode 100644 index 000000000..d5f281b7a --- /dev/null +++ b/docs/nightly/guide/en/publishing/web.html @@ -0,0 +1,227 @@ + + + + + + Web + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Publishing with Github Pages

    +

    To build our app and publish it to Github:

    +
      +
    • Make sure GitHub Pages is set up for your repo
    • +
    • Build your app with trunk build --release (include --public-url <repo-name> to update asset prefixes if using a project site)
    • +
    • Move your generated HTML/CSS/JS/Wasm from dist into the folder configured for Github Pages
    • +
    • Add and commit with git
    • +
    • Push to GitHub
    • +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/nightly/guide/en/searcher.js b/docs/nightly/guide/en/searcher.js new file mode 100644 index 000000000..d2b0aeed3 --- /dev/null +++ b/docs/nightly/guide/en/searcher.js @@ -0,0 +1,483 @@ +"use strict"; +window.search = window.search || {}; +(function search(search) { + // Search functionality + // + // You can use !hasFocus() to prevent keyhandling in your key + // event handlers while the user is typing their search. + + if (!Mark || !elasticlunr) { + return; + } + + //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + }; + } + + var search_wrap = document.getElementById('search-wrapper'), + searchbar = document.getElementById('searchbar'), + searchbar_outer = document.getElementById('searchbar-outer'), + searchresults = document.getElementById('searchresults'), + searchresults_outer = document.getElementById('searchresults-outer'), + searchresults_header = document.getElementById('searchresults-header'), + searchicon = document.getElementById('search-toggle'), + content = document.getElementById('content'), + + searchindex = null, + doc_urls = [], + results_options = { + teaser_word_count: 30, + limit_results: 30, + }, + search_options = { + bool: "AND", + expand: true, + fields: { + title: {boost: 1}, + body: {boost: 1}, + breadcrumbs: {boost: 0} + } + }, + mark_exclude = [], + marker = new Mark(content), + current_searchterm = "", + URL_SEARCH_PARAM = 'search', + URL_MARK_PARAM = 'highlight', + teaser_count = 0, + + SEARCH_HOTKEY_KEYCODE = 83, + ESCAPE_KEYCODE = 27, + DOWN_KEYCODE = 40, + UP_KEYCODE = 38, + SELECT_KEYCODE = 13; + + function hasFocus() { + return searchbar === document.activeElement; + } + + function removeChildren(elem) { + while (elem.firstChild) { + elem.removeChild(elem.firstChild); + } + } + + // Helper to parse a url into its building blocks. + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + return { + source: url, + protocol: a.protocol.replace(':',''), + host: a.hostname, + port: a.port, + params: (function(){ + var ret = {}; + var seg = a.search.replace(/^\?/,'').split('&'); + var len = seg.length, i = 0, s; + for (;i': '>', + '"': '"', + "'": ''' + }; + var repl = function(c) { return MAP[c]; }; + return function(s) { + return s.replace(/[&<>'"]/g, repl); + }; + })(); + + function formatSearchMetric(count, searchterm) { + if (count == 1) { + return count + " search result for '" + searchterm + "':"; + } else if (count == 0) { + return "No search results for '" + searchterm + "'."; + } else { + return count + " search results for '" + searchterm + "':"; + } + } + + function formatSearchResult(result, searchterms) { + var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); + teaser_count++; + + // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor + var url = doc_urls[result.ref].split("#"); + if (url.length == 1) { // no anchor found + url.push(""); + } + + // encodeURIComponent escapes all chars that could allow an XSS except + // for '. Due to that we also manually replace ' with its url-encoded + // representation (%27). + var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); + + return '' + result.doc.breadcrumbs + '' + + '' + + teaser + ''; + } + + function makeTeaser(body, searchterms) { + // The strategy is as follows: + // First, assign a value to each word in the document: + // Words that correspond to search terms (stemmer aware): 40 + // Normal words: 2 + // First word in a sentence: 8 + // Then use a sliding window with a constant number of words and count the + // sum of the values of the words within the window. Then use the window that got the + // maximum sum. If there are multiple maximas, then get the last one. + // Enclose the terms in . + var stemmed_searchterms = searchterms.map(function(w) { + return elasticlunr.stemmer(w.toLowerCase()); + }); + var searchterm_weight = 40; + var weighted = []; // contains elements of ["word", weight, index_in_document] + // split in sentences, then words + var sentences = body.toLowerCase().split('. '); + var index = 0; + var value = 0; + var searchterm_found = false; + for (var sentenceindex in sentences) { + var words = sentences[sentenceindex].split(' '); + value = 8; + for (var wordindex in words) { + var word = words[wordindex]; + if (word.length > 0) { + for (var searchtermindex in stemmed_searchterms) { + if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { + value = searchterm_weight; + searchterm_found = true; + } + }; + weighted.push([word, value, index]); + value = 2; + } + index += word.length; + index += 1; // ' ' or '.' if last word in sentence + }; + index += 1; // because we split at a two-char boundary '. ' + }; + + if (weighted.length == 0) { + return body; + } + + var window_weight = []; + var window_size = Math.min(weighted.length, results_options.teaser_word_count); + + var cur_sum = 0; + for (var wordindex = 0; wordindex < window_size; wordindex++) { + cur_sum += weighted[wordindex][1]; + }; + window_weight.push(cur_sum); + for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { + cur_sum -= weighted[wordindex][1]; + cur_sum += weighted[wordindex + window_size][1]; + window_weight.push(cur_sum); + }; + + if (searchterm_found) { + var max_sum = 0; + var max_sum_window_index = 0; + // backwards + for (var i = window_weight.length - 1; i >= 0; i--) { + if (window_weight[i] > max_sum) { + max_sum = window_weight[i]; + max_sum_window_index = i; + } + }; + } else { + max_sum_window_index = 0; + } + + // add around searchterms + var teaser_split = []; + var index = weighted[max_sum_window_index][2]; + for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { + var word = weighted[i]; + if (index < word[2]) { + // missing text from index to start of `word` + teaser_split.push(body.substring(index, word[2])); + index = word[2]; + } + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + index = word[2] + word[0].length; + teaser_split.push(body.substring(word[2], index)); + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + }; + + return teaser_split.join(''); + } + + function init(config) { + results_options = config.results_options; + search_options = config.search_options; + searchbar_outer = config.searchbar_outer; + doc_urls = config.doc_urls; + searchindex = elasticlunr.Index.load(config.index); + + // Set up events + searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); + searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); + document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); + // If the user uses the browser buttons, do the same as if a reload happened + window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; + // Suppress "submit" events so the page doesn't reload when the user presses Enter + document.addEventListener('submit', function(e) { e.preventDefault(); }, false); + + // If reloaded, do the search or mark again, depending on the current url parameters + doSearchOrMarkFromUrl(); + } + + function unfocusSearchbar() { + // hacky, but just focusing a div only works once + var tmp = document.createElement('input'); + tmp.setAttribute('style', 'position: absolute; opacity: 0;'); + searchicon.appendChild(tmp); + tmp.focus(); + tmp.remove(); + } + + // On reload or browser history backwards/forwards events, parse the url and do search or mark + function doSearchOrMarkFromUrl() { + // Check current URL for search request + var url = parseURL(window.location.href); + if (url.params.hasOwnProperty(URL_SEARCH_PARAM) + && url.params[URL_SEARCH_PARAM] != "") { + showSearch(true); + searchbar.value = decodeURIComponent( + (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); + searchbarKeyUpHandler(); // -> doSearch() + } else { + showSearch(false); + } + + if (url.params.hasOwnProperty(URL_MARK_PARAM)) { + var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); + marker.mark(words, { + exclude: mark_exclude + }); + + var markers = document.querySelectorAll("mark"); + function hide() { + for (var i = 0; i < markers.length; i++) { + markers[i].classList.add("fade-out"); + window.setTimeout(function(e) { marker.unmark(); }, 300); + } + } + for (var i = 0; i < markers.length; i++) { + markers[i].addEventListener('click', hide); + } + } + } + + // Eventhandler for keyevents on `document` + function globalKeyHandler(e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; } + + if (e.keyCode === ESCAPE_KEYCODE) { + e.preventDefault(); + searchbar.classList.remove("active"); + setSearchUrlParameters("", + (searchbar.value.trim() !== "") ? "push" : "replace"); + if (hasFocus()) { + unfocusSearchbar(); + } + showSearch(false); + marker.unmark(); + } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { + e.preventDefault(); + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { + e.preventDefault(); + unfocusSearchbar(); + searchresults.firstElementChild.classList.add("focus"); + } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE + || e.keyCode === UP_KEYCODE + || e.keyCode === SELECT_KEYCODE)) { + // not `:focus` because browser does annoying scrolling + var focused = searchresults.querySelector("li.focus"); + if (!focused) return; + e.preventDefault(); + if (e.keyCode === DOWN_KEYCODE) { + var next = focused.nextElementSibling; + if (next) { + focused.classList.remove("focus"); + next.classList.add("focus"); + } + } else if (e.keyCode === UP_KEYCODE) { + focused.classList.remove("focus"); + var prev = focused.previousElementSibling; + if (prev) { + prev.classList.add("focus"); + } else { + searchbar.select(); + } + } else { // SELECT_KEYCODE + window.location.assign(focused.querySelector('a')); + } + } + } + + function showSearch(yes) { + if (yes) { + search_wrap.classList.remove('hidden'); + searchicon.setAttribute('aria-expanded', 'true'); + } else { + search_wrap.classList.add('hidden'); + searchicon.setAttribute('aria-expanded', 'false'); + var results = searchresults.children; + for (var i = 0; i < results.length; i++) { + results[i].classList.remove("focus"); + } + } + } + + function showResults(yes) { + if (yes) { + searchresults_outer.classList.remove('hidden'); + } else { + searchresults_outer.classList.add('hidden'); + } + } + + // Eventhandler for search icon + function searchIconClickHandler() { + if (search_wrap.classList.contains('hidden')) { + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else { + showSearch(false); + } + } + + // Eventhandler for keyevents while the searchbar is focused + function searchbarKeyUpHandler() { + var searchterm = searchbar.value.trim(); + if (searchterm != "") { + searchbar.classList.add("active"); + doSearch(searchterm); + } else { + searchbar.classList.remove("active"); + showResults(false); + removeChildren(searchresults); + } + + setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); + + // Remove marks + marker.unmark(); + } + + // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . + // `action` can be one of "push", "replace", "push_if_new_search_else_replace" + // and replaces or pushes a new browser history item. + // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. + function setSearchUrlParameters(searchterm, action) { + var url = parseURL(window.location.href); + var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); + if (searchterm != "" || action == "push_if_new_search_else_replace") { + url.params[URL_SEARCH_PARAM] = searchterm; + delete url.params[URL_MARK_PARAM]; + url.hash = ""; + } else { + delete url.params[URL_MARK_PARAM]; + delete url.params[URL_SEARCH_PARAM]; + } + // A new search will also add a new history item, so the user can go back + // to the page prior to searching. A updated search term will only replace + // the url. + if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { + history.pushState({}, document.title, renderURL(url)); + } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { + history.replaceState({}, document.title, renderURL(url)); + } + } + + function doSearch(searchterm) { + + // Don't search the same twice + if (current_searchterm == searchterm) { return; } + else { current_searchterm = searchterm; } + + if (searchindex == null) { return; } + + // Do the actual search + var results = searchindex.search(searchterm, search_options); + var resultcount = Math.min(results.length, results_options.limit_results); + + // Display search metrics + searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); + + // Clear and insert results + var searchterms = searchterm.split(' '); + removeChildren(searchresults); + for(var i = 0; i < resultcount ; i++){ + var resultElem = document.createElement('li'); + resultElem.innerHTML = formatSearchResult(results[i], searchterms); + searchresults.appendChild(resultElem); + } + + // Display results + showResults(true); + } + + fetch(path_to_root + 'searchindex.json') + .then(response => response.json()) + .then(json => init(json)) + .catch(error => { // Try to load searchindex.js if fetch failed + var script = document.createElement('script'); + script.src = path_to_root + 'searchindex.js'; + script.onload = () => init(window.search); + document.head.appendChild(script); + }); + + // Exported functions + search.hasFocus = hasFocus; +})(window.search); diff --git a/docs/nightly/guide/en/searchindex.js b/docs/nightly/guide/en/searchindex.js new file mode 100644 index 000000000..83c00bcb3 --- /dev/null +++ b/docs/nightly/guide/en/searchindex.js @@ -0,0 +1 @@ +Object.assign(window.search, {"doc_urls":["index.html#introduction","index.html#features","index.html#stability","getting_started/index.html#getting-started","getting_started/index.html#prerequisites","getting_started/index.html#setup-guides","getting_started/desktop.html#desktop-overview","getting_started/desktop.html#support","getting_started/desktop.html#getting-started","getting_started/desktop.html#platform-specific-dependencies","getting_started/desktop.html#creating-a-project","getting_started/web.html#web","getting_started/web.html#support","getting_started/web.html#tooling","getting_started/web.html#creating-a-project","getting_started/ssr.html#server-side-rendering","getting_started/ssr.html#setup","getting_started/ssr.html#multithreaded-support","getting_started/fullstack.html#fullstack","getting_started/liveview.html#liveview","getting_started/liveview.html#support","getting_started/liveview.html#setup","getting_started/tui.html#terminal-ui","getting_started/tui.html#support","getting_started/tui.html#getting-set-up","getting_started/mobile.html#mobile-app","getting_started/mobile.html#support","getting_started/mobile.html#getting-set-up","getting_started/hot_reload.html#setting-up-hot-reload","getting_started/hot_reload.html#web","getting_started/hot_reload.html#setup","getting_started/hot_reload.html#usage","getting_started/hot_reload.html#desktopliveviewtuiserver","getting_started/hot_reload.html#setup","getting_started/hot_reload.html#usage","getting_started/hot_reload.html#limitations","describing_ui/index.html#describing-the-ui","describing_ui/index.html#rsx-features","describing_ui/special_attributes.html#special-attributes","describing_ui/special_attributes.html#the-html-escape-hatch","describing_ui/special_attributes.html#boolean-attributes","describing_ui/components.html#components","describing_ui/component_props.html#component-props","describing_ui/component_props.html#deriveprops","describing_ui/component_props.html#prop-options","describing_ui/component_props.html#the-inline_props-macro","describing_ui/component_children.html#component-children","describing_ui/component_children.html#the-children-field","interactivity/index.html#interactivity","interactivity/event_handlers.html#event-handlers","interactivity/event_handlers.html#the-event-object","interactivity/event_handlers.html#prevent-default","interactivity/event_handlers.html#handler-props","interactivity/hooks.html#hooks-and-component-state","interactivity/hooks.html#use_state-hook","interactivity/hooks.html#rules-of-hooks","interactivity/hooks.html#use_ref-hook","interactivity/user_input.html#user-input","interactivity/user_input.html#controlled-inputs","interactivity/user_input.html#uncontrolled-inputs","interactivity/sharing_state.html#sharing-state","interactivity/sharing_state.html#lifting-state","interactivity/sharing_state.html#using-context","interactivity/custom_hooks.html#custom-hooks","interactivity/custom_hooks.html#composing-hooks","interactivity/custom_hooks.html#custom-hook-logic","interactivity/custom_hooks.html#hook-anti-patterns","interactivity/dynamic_rendering.html#dynamic-rendering","interactivity/dynamic_rendering.html#conditional-rendering","interactivity/dynamic_rendering.html#rendering-nothing","interactivity/dynamic_rendering.html#rendering-lists","interactivity/router.html#router","interactivity/router.html#what-is-it","interactivity/router.html#using-the-router","interactivity/router.html#links","interactivity/router.html#more-reading","async/index.html#working-with-async","async/index.html#the-runtime","async/use_future.html#usefuture","async/use_future.html#restarting-the-future","async/use_future.html#dependencies","async/use_coroutine.html#coroutines","async/use_coroutine.html#use_coroutine","async/use_coroutine.html#yielding-values","async/use_coroutine.html#sending-values","async/use_coroutine.html#automatic-injection-into-the-context-api","async/spawn.html#spawning-futures","async/spawn.html#spawning-tokio-tasks","best_practices/index.html#best-practices","best_practices/index.html#reusable-components","best_practices/index.html#minimize-state-dependencies","best_practices/error_handling.html#error-handling","best_practices/error_handling.html#the-simplest--returning-none","best_practices/error_handling.html#early-return-on-result","best_practices/error_handling.html#match-results","best_practices/error_handling.html#passing-error-states-through-components","best_practices/error_handling.html#going-global","best_practices/antipatterns.html#antipatterns","best_practices/antipatterns.html#unnecessarily-nested-fragments","best_practices/antipatterns.html#incorrect-iterator-keys","best_practices/antipatterns.html#avoid-interior-mutability-in-props","best_practices/antipatterns.html#avoid-updating-state-during-render","publishing/index.html#publishing","publishing/desktop.html#publishing","publishing/desktop.html#install-cargo-bundle","publishing/desktop.html#setting-up-your-project","publishing/desktop.html#building","publishing/web.html#publishing-with-github-pages","fullstack/index.html#fullstack-development","fullstack/index.html#summary-of-existing-approaches","fullstack/index.html#a-new-approach","fullstack/getting_started.html#getting-started","fullstack/getting_started.html#setup","fullstack/getting_started.html#hydration","fullstack/getting_started.html#sycronizing-props-between-the-server-and-client","fullstack/server_functions.html#communicating-with-the-server","fullstack/server_functions.html#conclusion","custom_renderer/index.html#custom-renderer","custom_renderer/index.html#the-specifics","custom_renderer/index.html#templates","custom_renderer/index.html#mutations","custom_renderer/index.html#node-storage","custom_renderer/index.html#event-loop","custom_renderer/index.html#custom-raw-elements","custom_renderer/index.html#native-core","custom_renderer/index.html#the-realdom","custom_renderer/index.html#layout","custom_renderer/index.html#text-editing","custom_renderer/index.html#conclusion","contributing/index.html#contributing","contributing/index.html#improving-docs","contributing/index.html#working-on-the-ecosystem","contributing/index.html#bugs--features","contributing/index.html#tools","contributing/project_structure.html#project-struture","contributing/project_structure.html#renderers","contributing/project_structure.html#state-managementhooks","contributing/project_structure.html#core-utilities","contributing/project_structure.html#native-renderer-utilities","contributing/project_structure.html#web-renderer-tooling","contributing/project_structure.html#developer-tooling","contributing/walkthrough_readme.html#walkthrough-of-the-hello-world-example-internals","contributing/walkthrough_readme.html#the-source-file","contributing/walkthrough_readme.html#the-rsx-macro","contributing/walkthrough_readme.html#launching-the-app","contributing/walkthrough_readme.html#the-virtual-dom","contributing/walkthrough_readme.html#conclusion","contributing/guiding_principles.html#overall-goals","contributing/guiding_principles.html#cross-platform","contributing/guiding_principles.html#performance","contributing/guiding_principles.html#type-safety","contributing/guiding_principles.html#developer-experience","contributing/roadmap.html#roadmap--feature-set","contributing/roadmap.html#features","contributing/roadmap.html#roadmap","contributing/roadmap.html#work-in-progress"],"index":{"documentStore":{"docInfo":{"0":{"body":73,"breadcrumbs":2,"title":1},"1":{"body":113,"breadcrumbs":2,"title":1},"10":{"body":58,"breadcrumbs":5,"title":2},"100":{"body":44,"breadcrumbs":7,"title":4},"101":{"body":22,"breadcrumbs":8,"title":5},"102":{"body":0,"breadcrumbs":2,"title":1},"103":{"body":28,"breadcrumbs":3,"title":1},"104":{"body":68,"breadcrumbs":5,"title":3},"105":{"body":46,"breadcrumbs":5,"title":3},"106":{"body":67,"breadcrumbs":3,"title":1},"107":{"body":40,"breadcrumbs":5,"title":3},"108":{"body":25,"breadcrumbs":3,"title":2},"109":{"body":247,"breadcrumbs":4,"title":3},"11":{"body":59,"breadcrumbs":4,"title":1},"110":{"body":82,"breadcrumbs":3,"title":2},"111":{"body":8,"breadcrumbs":5,"title":2},"112":{"body":156,"breadcrumbs":4,"title":1},"113":{"body":162,"breadcrumbs":4,"title":1},"114":{"body":237,"breadcrumbs":8,"title":5},"115":{"body":283,"breadcrumbs":5,"title":2},"116":{"body":22,"breadcrumbs":4,"title":1},"117":{"body":45,"breadcrumbs":4,"title":2},"118":{"body":64,"breadcrumbs":3,"title":1},"119":{"body":55,"breadcrumbs":3,"title":1},"12":{"body":29,"breadcrumbs":4,"title":1},"120":{"body":56,"breadcrumbs":3,"title":1},"121":{"body":483,"breadcrumbs":4,"title":2},"122":{"body":158,"breadcrumbs":4,"title":2},"123":{"body":55,"breadcrumbs":5,"title":3},"124":{"body":21,"breadcrumbs":4,"title":2},"125":{"body":829,"breadcrumbs":3,"title":1},"126":{"body":15,"breadcrumbs":3,"title":1},"127":{"body":72,"breadcrumbs":4,"title":2},"128":{"body":33,"breadcrumbs":3,"title":1},"129":{"body":33,"breadcrumbs":2,"title":1},"13":{"body":42,"breadcrumbs":4,"title":1},"130":{"body":14,"breadcrumbs":3,"title":2},"131":{"body":32,"breadcrumbs":3,"title":2},"132":{"body":51,"breadcrumbs":3,"title":2},"133":{"body":98,"breadcrumbs":2,"title":1},"134":{"body":12,"breadcrumbs":5,"title":2},"135":{"body":84,"breadcrumbs":4,"title":1},"136":{"body":43,"breadcrumbs":5,"title":2},"137":{"body":45,"breadcrumbs":5,"title":2},"138":{"body":36,"breadcrumbs":6,"title":3},"139":{"body":15,"breadcrumbs":6,"title":3},"14":{"body":61,"breadcrumbs":5,"title":2},"140":{"body":38,"breadcrumbs":5,"title":2},"141":{"body":32,"breadcrumbs":8,"title":5},"142":{"body":52,"breadcrumbs":5,"title":2},"143":{"body":360,"breadcrumbs":5,"title":2},"144":{"body":29,"breadcrumbs":5,"title":2},"145":{"body":402,"breadcrumbs":5,"title":2},"146":{"body":35,"breadcrumbs":4,"title":1},"147":{"body":21,"breadcrumbs":5,"title":2},"148":{"body":39,"breadcrumbs":5,"title":2},"149":{"body":57,"breadcrumbs":4,"title":1},"15":{"body":21,"breadcrumbs":8,"title":3},"150":{"body":33,"breadcrumbs":5,"title":2},"151":{"body":91,"breadcrumbs":5,"title":2},"152":{"body":108,"breadcrumbs":5,"title":3},"153":{"body":227,"breadcrumbs":3,"title":1},"154":{"body":97,"breadcrumbs":3,"title":1},"155":{"body":77,"breadcrumbs":4,"title":2},"16":{"body":184,"breadcrumbs":6,"title":1},"17":{"body":57,"breadcrumbs":7,"title":2},"18":{"body":0,"breadcrumbs":4,"title":1},"19":{"body":20,"breadcrumbs":4,"title":1},"2":{"body":34,"breadcrumbs":2,"title":1},"20":{"body":33,"breadcrumbs":4,"title":1},"21":{"body":176,"breadcrumbs":4,"title":1},"22":{"body":24,"breadcrumbs":6,"title":2},"23":{"body":49,"breadcrumbs":5,"title":1},"24":{"body":141,"breadcrumbs":7,"title":3},"25":{"body":7,"breadcrumbs":5,"title":2},"26":{"body":52,"breadcrumbs":4,"title":1},"27":{"body":122,"breadcrumbs":6,"title":3},"28":{"body":36,"breadcrumbs":8,"title":4},"29":{"body":10,"breadcrumbs":5,"title":1},"3":{"body":6,"breadcrumbs":4,"title":2},"30":{"body":12,"breadcrumbs":5,"title":1},"31":{"body":20,"breadcrumbs":5,"title":1},"32":{"body":32,"breadcrumbs":5,"title":1},"33":{"body":9,"breadcrumbs":5,"title":1},"34":{"body":15,"breadcrumbs":5,"title":1},"35":{"body":29,"breadcrumbs":5,"title":1},"36":{"body":61,"breadcrumbs":4,"title":2},"37":{"body":311,"breadcrumbs":4,"title":2},"38":{"body":6,"breadcrumbs":6,"title":2},"39":{"body":92,"breadcrumbs":7,"title":3},"4":{"body":75,"breadcrumbs":3,"title":1},"40":{"body":72,"breadcrumbs":6,"title":2},"41":{"body":134,"breadcrumbs":4,"title":1},"42":{"body":18,"breadcrumbs":5,"title":2},"43":{"body":200,"breadcrumbs":4,"title":1},"44":{"body":186,"breadcrumbs":5,"title":2},"45":{"body":83,"breadcrumbs":5,"title":2},"46":{"body":65,"breadcrumbs":6,"title":2},"47":{"body":56,"breadcrumbs":6,"title":2},"48":{"body":20,"breadcrumbs":2,"title":1},"49":{"body":67,"breadcrumbs":5,"title":2},"5":{"body":49,"breadcrumbs":4,"title":2},"50":{"body":156,"breadcrumbs":5,"title":2},"51":{"body":65,"breadcrumbs":5,"title":2},"52":{"body":66,"breadcrumbs":5,"title":2},"53":{"body":43,"breadcrumbs":7,"title":3},"54":{"body":186,"breadcrumbs":6,"title":2},"55":{"body":212,"breadcrumbs":6,"title":2},"56":{"body":129,"breadcrumbs":6,"title":2},"57":{"body":17,"breadcrumbs":5,"title":2},"58":{"body":78,"breadcrumbs":5,"title":2},"59":{"body":92,"breadcrumbs":5,"title":2},"6":{"body":33,"breadcrumbs":5,"title":2},"60":{"body":11,"breadcrumbs":5,"title":2},"61":{"body":286,"breadcrumbs":5,"title":2},"62":{"body":208,"breadcrumbs":5,"title":2},"63":{"body":23,"breadcrumbs":5,"title":2},"64":{"body":183,"breadcrumbs":5,"title":2},"65":{"body":181,"breadcrumbs":6,"title":3},"66":{"body":135,"breadcrumbs":6,"title":3},"67":{"body":25,"breadcrumbs":5,"title":2},"68":{"body":165,"breadcrumbs":5,"title":2},"69":{"body":32,"breadcrumbs":5,"title":2},"7":{"body":75,"breadcrumbs":4,"title":1},"70":{"body":302,"breadcrumbs":5,"title":2},"71":{"body":29,"breadcrumbs":3,"title":1},"72":{"body":42,"breadcrumbs":2,"title":0},"73":{"body":104,"breadcrumbs":4,"title":2},"74":{"body":21,"breadcrumbs":3,"title":1},"75":{"body":13,"breadcrumbs":4,"title":2},"76":{"body":16,"breadcrumbs":3,"title":2},"77":{"body":40,"breadcrumbs":2,"title":1},"78":{"body":93,"breadcrumbs":3,"title":1},"79":{"body":12,"breadcrumbs":4,"title":2},"8":{"body":0,"breadcrumbs":5,"title":2},"80":{"body":35,"breadcrumbs":3,"title":1},"81":{"body":41,"breadcrumbs":3,"title":1},"82":{"body":98,"breadcrumbs":3,"title":1},"83":{"body":77,"breadcrumbs":4,"title":2},"84":{"body":265,"breadcrumbs":4,"title":2},"85":{"body":22,"breadcrumbs":6,"title":4},"86":{"body":84,"breadcrumbs":5,"title":2},"87":{"body":36,"breadcrumbs":6,"title":3},"88":{"body":0,"breadcrumbs":4,"title":2},"89":{"body":38,"breadcrumbs":4,"title":2},"9":{"body":141,"breadcrumbs":6,"title":3},"90":{"body":32,"breadcrumbs":5,"title":3},"91":{"body":28,"breadcrumbs":6,"title":2},"92":{"body":54,"breadcrumbs":7,"title":3},"93":{"body":63,"breadcrumbs":7,"title":3},"94":{"body":69,"breadcrumbs":6,"title":2},"95":{"body":60,"breadcrumbs":9,"title":5},"96":{"body":160,"breadcrumbs":6,"title":2},"97":{"body":17,"breadcrumbs":4,"title":1},"98":{"body":78,"breadcrumbs":6,"title":3},"99":{"body":71,"breadcrumbs":6,"title":3}},"docs":{"0":{"body":"dioxuslogo Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust. This guide will help you get started with writing Dioxus apps for the Web, Desktop, Mobile, and more. fn app(cx: Scope) -> Element { let mut count = use_state(cx, || 0); cx.render(rsx!( h1 { \"High-Five counter: {count}\" } button { onclick: move |_| count += 1, \"Up high!\" } button { onclick: move |_| count -= 1, \"Down low!\" } ))\n} Dioxus is heavily inspired by React. If you know React, getting started with Dioxus will be a breeze. This guide assumes you already know some Rust ! If not, we recommend reading the book to learn Rust first.","breadcrumbs":"Introduction » Introduction","id":"0","title":"Introduction"},"1":{"body":"Desktop apps running natively (no Electron!) in less than 10 lines of code. Incredibly ergonomic and powerful state management. Comprehensive inline documentation – hover and guides for all HTML elements, listeners, and events. Extremely memory efficient – 0 global allocations for steady-state components. Multi-channel asynchronous scheduler for first-class async support. And more! Read the full release post . Multiplatform Dioxus is a portable toolkit, meaning the Core implementation can run anywhere with no platform-dependent linking. Unlike many other Rust frontend toolkits, Dioxus is not intrinsically linked to WebSys. In fact, every element and event listener can be swapped out at compile time. By default, Dioxus ships with the html feature enabled, but this can be disabled depending on your target renderer. Right now, we have several 1st-party renderers: WebSys (for WASM): Great support Tao/Tokio (for Desktop apps): Good support Tao/Tokio (for Mobile apps): Poor support SSR (for generating static markup) TUI/Rink (for terminal-based apps): Experimental","breadcrumbs":"Introduction » Features","id":"1","title":"Features"},"10":{"body":"Create a new crate: cargo new --bin demo\ncd demo Add Dioxus and the desktop renderer as dependencies (this will edit your Cargo.toml): cargo add dioxus\ncargo add dioxus-desktop Edit your main.rs: #![allow(non_snake_case)]\n// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types\nuse dioxus::prelude::*; fn main() { // launch the dioxus app in a webview dioxus_desktop::launch(App);\n} // define a component that renders a div with the text \"Hello, world!\"\nfn App(cx: Scope) -> Element { cx.render(rsx! { div { \"Hello, world!\" } })\n}","breadcrumbs":"Getting Started » Desktop » Creating a Project","id":"10","title":"Creating a Project"},"100":{"body":"While it is technically acceptable to have a Mutex or a RwLock in the props, they will be difficult to use. Suppose you have a struct User containing the field username: String. If you pass a Mutex prop to a UserComponent component, that component may wish to pass the username as a &str prop to a child component. However, it cannot pass that borrowed field down, since it only would live as long as the Mutex's lock, which belongs to the UserComponent function. Therefore, the component will be forced to clone the username field.","breadcrumbs":"Best Practices » Antipatterns » Avoid Interior Mutability in Props","id":"100","title":"Avoid Interior Mutability in Props"},"101":{"body":"Every time you update the state, Dioxus needs to re-render the component – this is inefficient! Consider refactoring your code to avoid this. Also, if you unconditionally update the state during render, it will be re-rendered in an infinite loop.","breadcrumbs":"Best Practices » Antipatterns » Avoid Updating State During Render","id":"101","title":"Avoid Updating State During Render"},"102":{"body":"","breadcrumbs":"Publishing » Publishing","id":"102","title":"Publishing"},"103":{"body":"Congrats! You've made your first Dioxus app that actually does some pretty cool stuff. This app uses your operating system's WebView library, so it's portable to be distributed for other platforms. In this section, we'll cover how to bundle your app for macOS, Windows, and Linux.","breadcrumbs":"Publishing » Desktop » Publishing","id":"103","title":"Publishing"},"104":{"body":"The first thing we'll do is install cargo-bundle . This extension to cargo will make it very easy to package our app for the various platforms. According to the cargo-bundle github page, \"cargo-bundle is a tool used to generate installers or app bundles for GUI executables built with cargo. It can create .app bundles for Mac OS X and iOS, .deb packages for Linux, and .msi installers for Windows (note however that iOS and Windows support is still experimental). Support for creating .rpm packages (for Linux) and .apk packages (for Android) is still pending.\" To install, simply run cargo install cargo-bundle","breadcrumbs":"Publishing » Desktop » Install cargo-bundle","id":"104","title":"Install cargo-bundle"},"105":{"body":"To get a project setup for bundling, we need to add some flags to our Cargo.toml file. [package]\nname = \"example\"\n# ...other fields... [package.metadata.bundle]\nname = \"DogSearch\"\nidentifier = \"com.dogs.dogsearch\"\nversion = \"1.0.0\"\ncopyright = \"Copyright (c) Jane Doe 2016. All rights reserved.\"\ncategory = \"Developer Tool\"\nshort_description = \"Easily search for Dog photos\"\nlong_description = \"\"\"\nThis app makes it quick and easy to browse photos of dogs from over 200 bree\n\"\"\"","breadcrumbs":"Publishing » Desktop » Setting up your project","id":"105","title":"Setting up your project"},"106":{"body":"Following cargo-bundle's instructions, we simply cargo-bundle --release to produce a final app with all the optimizations and assets builtin. Once you've ran cargo-bundle --release, your app should be accessible in target/release/bundle//. For example, a macOS app would look like this: Published App Nice! And it's only 4.8 Mb – extremely lean!! Because Dioxus leverages your platform's native WebView, Dioxus apps are extremely memory efficient and won't waste your battery. Note: not all CSS works the same on all platforms. Make sure to view your app's CSS on each platform – or web browser (Firefox, Chrome, Safari) before publishing.","breadcrumbs":"Publishing » Desktop » Building","id":"106","title":"Building"},"107":{"body":"To build our app and publish it to Github: Make sure GitHub Pages is set up for your repo Build your app with trunk build --release (include --public-url to update asset prefixes if using a project site) Move your generated HTML/CSS/JS/Wasm from dist into the folder configured for Github Pages Add and commit with git Push to GitHub","breadcrumbs":"Publishing » Web » Publishing with Github Pages","id":"107","title":"Publishing with Github Pages"},"108":{"body":"So far you have learned about three different approaches to target the web with Dioxus: Client-side rendering with dioxus-web Server-side rendering with dioxus-liveview Server-side static HTML generation with dioxus-ssr","breadcrumbs":"Fullstack » Fullstack development","id":"108","title":"Fullstack development"},"109":{"body":"Each approach has its tradeoffs: Client-side rendering With Client side rendering, you send the entire content of your application to the client, and then the client generates all of the HTML of the page dynamically. This means that the page will be blank until the JavaScript bundle has loaded and the application has initialized. This can result in slower first render times and makes the page less SEO-friendly . SEO stands for Search Engine Optimization. It refers to the practice of making your website more likely to appear in search engine results. Search engines like Google and Bing use web crawlers to index the content of websites. Most of these crawlers are not able to run JavaScript, so they will not be able to index the content of your page if it is rendered client-side. Client-side rendered applications need to use weakly typed requests to communicate with the server Client-side rendering is a good starting point for most applications. It is well supported and makes it easy to communicate with the client/browser APIs Liveview Liveview rendering communicates with the server over a WebSocket connection. It essentially moves all of the work that Client-side rendering does to the server. This makes it easy to communicate with the server, but more difficult to communicate with the client/browser APIS . Each interaction also requires a message to be sent to the server and back which can cause issues with latency . Because Liveview uses a websocket to render, the page will be blank until the WebSocket connection has been established and the first renderer has been sent form the websocket. Just like with client side rendering, this can make the page less SEO-friendly . Because the page is rendered on the server and the page is sent to the client piece by piece, you never need to send the entire application to the client. The initial load time can be faster than client-side rendering with large applications because Liveview only needs to send a constant small websocket script regardless of the size of the application. Liveview is a good fit for applications that already need to communicate with the server frequently (like real time collaborative apps), but don't need to communicate with as many client/browser APIs Server-side rendering Server-side rendering generates all of the HTML of the page on the server before the page is sent to the client. This means that the page will be fully rendered when it is sent to the client. This results in a faster first render time and makes the page more SEO-friendly. However, it only works for static pages . Server-side rendering is not a good fit for purely static sites like a blog","breadcrumbs":"Fullstack » Summary of Existing Approaches","id":"109","title":"Summary of Existing Approaches"},"11":{"body":"Build single-page applications that run in the browser with Dioxus. To run on the Web, your app must be compiled to WebAssembly and depend on the dioxus and dioxus-web crates. A build of Dioxus for the web will be roughly equivalent to the size of a React build (70kb vs 65kb) but it will load significantly faster because WebAssembly can be compiled as it is streamed . Examples: TodoMVC ECommerce TodoMVC example Note: Because of the limitations of Wasm, not every crate will work with your web apps, so you'll need to make sure that your crates work without native system calls (timers, IO, etc).","breadcrumbs":"Getting Started » Web » Web","id":"11","title":"Web"},"110":{"body":"Each of these approaches has its tradeoffs. What if we could combine the best parts of each approach? Fast initial render time like SSR Works well with SEO like SSR Type safe easy communication with the server like Liveview Access to the client/browser APIs like Client-side rendering Fast interactivity like Client-side rendering We can achieve this by rendering the initial page on the server (SSR) and then taking over rendering on the client (Client-side rendering). Taking over rendering on the client is called hydration . Finally, we can use server functions to communicate with the server in a type-safe way. This approach uses both the dioxus-web and dioxus-ssr crates. To integrate those two packages and axum, warp, or salvo, Dioxus provides the dioxus-fullstack crate.","breadcrumbs":"Fullstack » A New Approach","id":"110","title":"A New Approach"},"111":{"body":"This guide assumes you read the Web guide and installed the Dioxus-cli","breadcrumbs":"Fullstack » Getting Started » Getting Started","id":"111","title":"Getting Started"},"112":{"body":"For this guide, we're going to show how to use Dioxus with Axum , but dioxus-fullstack also integrates with the Warp and Salvo web frameworks. Make sure you have Rust and Cargo installed, and then create a new project: cargo new --bin demo\ncd demo Add dioxus and dioxus-fullstack as dependencies: cargo add dioxus\ncargo add dioxus-fullstack --features axum, ssr Next, add all the Axum dependencies. This will be different if you're using a different Web Framework cargo add tokio --features full\ncargo add axum Your dependencies should look roughly like this: [dependencies]\naxum = \"*\"\ndioxus = { version = \"*\" }\ndioxus-fullstack = { version = \"*\", features = [\"axum\", \"ssr\"] }\ntokio = { version = \"*\", features = [\"full\"] } Now, set up your Axum app to serve the Dioxus app. #![allow(non_snake_case, unused)]\nuse dioxus::prelude::*; #[tokio::main]\nasync fn main() { #[cfg(feature = \"ssr\")] { use dioxus_fullstack::prelude::*; let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); axum::Server::bind(&addr) .serve( axum::Router::new() .serve_dioxus_application(\"\", ServeConfigBuilder::new(app, ())) .into_make_service(), ) .await .unwrap(); }\n} fn app(cx: Scope) -> Element { let mut count = use_state(cx, || 0); cx.render(rsx! { h1 { \"High-Five counter: {count}\" } button { onclick: move |_| count += 1, \"Up high!\" } button { onclick: move |_| count -= 1, \"Down low!\" } })\n} Now, run your app with cargo run and open http://localhost:8080 in your browser. You should see a server-side rendered page with a counter.","breadcrumbs":"Fullstack » Getting Started » Setup","id":"112","title":"Setup"},"113":{"body":"Right now, the page is static. We can't interact with the buttons. To fix this, we can hydrate the page with dioxus-web. First, modify your Cargo.toml to include two features, one for the server called ssr, and one for the client called web. [dependencies]\n# Common dependancies\ndioxus = { version = \"*\" }\ndioxus-fullstack = { version = \"*\" } # Web dependancies\ndioxus-web = { version = \"*\", features=[\"hydrate\"], optional = true } # Server dependancies\naxum = { version = \"0.6.12\", optional = true }\ntokio = { version = \"1.27.0\", features = [\"full\"], optional = true } [features]\ndefault = []\nssr = [\"axum\", \"tokio\", \"dioxus-fullstack/axum\"]\nweb = [\"dioxus-web\"] Next, we need to modify our main.rs to use either hydrate on the client or render on the server depending on the active features. #![allow(non_snake_case, unused)]\nuse dioxus::prelude::*; fn main() { #[cfg(feature = \"web\")] dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); #[cfg(feature = \"ssr\")] { use dioxus_fullstack::prelude::*; tokio::runtime::Runtime::new() .unwrap() .block_on(async move { let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); axum::Server::bind(&addr) .serve( axum::Router::new() .serve_dioxus_application(\"\", ServeConfigBuilder::new(app, ())) .into_make_service(), ) .await .unwrap(); }); }\n} fn app(cx: Scope) -> Element { let mut count = use_state(cx, || 0); cx.render(rsx! { h1 { \"High-Five counter: {count}\" } button { onclick: move |_| count += 1, \"Up high!\" } button { onclick: move |_| count -= 1, \"Down low!\" } })\n} Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see the same page as before, but now you can interact with the buttons!","breadcrumbs":"Fullstack » Getting Started » Hydration","id":"113","title":"Hydration"},"114":{"body":"Let's make the initial count of the counter dynamic based on the current page. Modifying the server To do this, we must remove the serve_dioxus_application and replace it with a custom implementation of its four key functions: Serve static WASM and JS files with serve_static_assets Register server functions with register_server_fns (more information on server functions later) Connect to the hot reload server with connect_hot_reload A custom route that uses SSRState to server-side render the application Modifying the client The only thing we need to change on the client is the props. dioxus-fullstack will automatically serialize the props it uses to server render the app and send them to the client. In the client section of main.rs, we need to add get_root_props_from_document to deserialize the props before we hydrate the app. #![allow(non_snake_case, unused)]\nuse dioxus::prelude::*;\nuse dioxus_fullstack::prelude::*; fn main() { #[cfg(feature = \"web\")] dioxus_web::launch_with_props( app, // Get the root props from the document get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); #[cfg(feature = \"ssr\")] { use axum::extract::Path; use axum::extract::State; use axum::routing::get; tokio::runtime::Runtime::new() .unwrap() .block_on(async move { let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); axum::Server::bind(&addr) .serve( axum::Router::new() // Serve the dist folder with the static javascript and WASM files created by the dixous CLI .serve_static_assets(\"./dist\") // Register server functions .register_server_fns(\"\") // Connect to the hot reload server in debug mode .connect_hot_reload() // Render the application. This will serialize the root props (the intial count) into the HTML .route( \"/\", get(move | State(ssr_state): State| async move { axum::body::Full::from( ssr_state.render( &ServeConfigBuilder::new( app, 0, ) .build(), ) )}), ) // Render the application with a different intial count .route( \"/:initial_count\", get(move |Path(intial_count): Path, State(ssr_state): State| async move { axum::body::Full::from( ssr_state.render( &ServeConfigBuilder::new( app, intial_count, ) .build(), ) )}), ) .with_state(SSRState::default()) .into_make_service(), ) .await .unwrap(); }); }\n} fn app(cx: Scope) -> Element { let mut count = use_state(cx, || *cx.props); cx.render(rsx! { h1 { \"High-Five counter: {count}\" } button { onclick: move |_| count += 1, \"Up high!\" } button { onclick: move |_| count -= 1, \"Down low!\" } })\n} Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. Navigate to http://localhost:8080/1 and you should see the counter start at 1. Navigate to http://localhost:8080/2 and you should see the counter start at 2.","breadcrumbs":"Fullstack » Getting Started » Sycronizing props between the server and client","id":"114","title":"Sycronizing props between the server and client"},"115":{"body":"dixous-server provides server functions that allow you to call an automatically generated API on the server from the client as if it were a local function. To make a server function, simply add the #[server(YourUniqueType)] attribute to a function. The function must: Be an async function Have arguments and a return type that both implement serialize and deserialize (with serde ). Return a Result with an error type of ServerFnError You must call register on the type you passed into the server macro in your main function before starting your server to tell Dioxus about the server function. Let's continue building on the app we made in the getting started guide. We will add a server function to our app that allows us to double the count on the server. First, add serde as a dependency: cargo add serde Next, add the server function to your main.rs: #![allow(non_snake_case, unused)]\nuse dioxus::prelude::*;\nuse dioxus_fullstack::prelude::*; fn main() { #[cfg(feature = \"web\")] dioxus_web::launch_with_props( app, // Get the root props from the document get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); #[cfg(feature = \"ssr\")] { use axum::extract::Path; use axum::extract::State; use axum::routing::get; // Register the server function before starting the server DoubleServer::register().unwrap(); tokio::runtime::Runtime::new() .unwrap() .block_on(async move { let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); axum::Server::bind(&addr) .serve( axum::Router::new() // Serve the dist folder with the static javascript and WASM files created by the dixous CLI .serve_static_assets(\"./dist\") // Register server functions .register_server_fns(\"\") // Connect to the hot reload server in debug mode .connect_hot_reload() // Render the application. This will serialize the root props (the intial count) into the HTML .route( \"/\", get(move |Path(intial_count): Path, State(ssr_state): State| async move { axum::body::Full::from( ssr_state.render( &ServeConfigBuilder::new( app, intial_count, ) .build(), ) )}), ) // Render the application with a different intial count .route( \"/:initial_count\", get(move |Path(intial_count): Path, State(ssr_state): State| async move { axum::body::Full::from( ssr_state.render( &ServeConfigBuilder::new( app, intial_count, ) .build(), ) )}), ) .with_state(SSRState::default()) .into_make_service(), ) .await .unwrap(); }); }\n} fn app(cx: Scope) -> Element { let mut count = use_state(cx, || *cx.props); cx.render(rsx! { h1 { \"High-Five counter: {count}\" } button { onclick: move |_| count += 1, \"Up high!\" } button { onclick: move |_| count -= 1, \"Down low!\" } button { onclick: move |_| { to_owned![count]; async move { // Call the server function just like a local async function if let Ok(new_count) = double_server(*count.current()).await { count.set(new_count); } } }, \"Double\" } })\n} #[server(DoubleServer)]\nasync fn double_server(number: usize) -> Result { // Perform some expensive computation or access a database on the server tokio::time::sleep(std::time::Duration::from_secs(1)).await; let result = number * 2; println!(\"server calculated {result}\"); Ok(result)\n} Now, build your client-side bundle with dioxus build --features web and run your server with cargo run --features ssr. You should see a new button that multiplies the count by 2.","breadcrumbs":"Fullstack » Communicating with the Server » Communicating with the server","id":"115","title":"Communicating with the server"},"116":{"body":"That's it! You've created a full-stack Dioxus app. You can find more examples of full-stack apps and information about how to integrate with other frameworks and desktop renderers in the dioxus-fullstack examples directory .","breadcrumbs":"Fullstack » Communicating with the Server » Conclusion","id":"116","title":"Conclusion"},"117":{"body":"Dioxus is an incredibly portable framework for UI development. The lessons, knowledge, hooks, and components you acquire over time can always be used for future projects. However, sometimes those projects cannot leverage a supported renderer or you need to implement your own better renderer. Great news: the design of the renderer is entirely up to you! We provide suggestions and inspiration with the 1st party renderers, but only really require processing Mutations and sending UserEvents.","breadcrumbs":"Custom Renderer » Custom Renderer","id":"117","title":"Custom Renderer"},"118":{"body":"Implementing the renderer is fairly straightforward. The renderer needs to: Handle the stream of edits generated by updates to the virtual DOM Register listeners and pass events into the virtual DOM's event system Essentially, your renderer needs to process edits and generate events to update the VirtualDOM. From there, you'll have everything needed to render the VirtualDOM to the screen. Internally, Dioxus handles the tree relationship, diffing, memory management, and the event system, leaving as little as possible required for renderers to implement themselves. For reference, check out the javascript interpreter or tui renderer as a starting point for your custom renderer.","breadcrumbs":"Custom Renderer » The specifics:","id":"118","title":"The specifics:"},"119":{"body":"Dioxus is built around the concept of Templates . Templates describe a UI tree known at compile time with dynamic parts filled at runtime. This is useful internally to make skip diffing static nodes, but it is also useful for the renderer to reuse parts of the UI tree. This can be useful for things like a list of items. Each item could contain some static parts and some dynamic parts. The renderer can use the template to create a static part of the UI once, clone it for each element in the list, and then fill in the dynamic parts.","breadcrumbs":"Custom Renderer » Templates","id":"119","title":"Templates"},"12":{"body":"The Web is the best-supported target platform for Dioxus. Because your app will be compiled to WASM you have access to browser APIs through wasm-bingen . Dioxus provides hydration to resume apps that are rendered on the server. See the fullstack getting started guide for more information.","breadcrumbs":"Getting Started » Web » Support","id":"12","title":"Support"},"120":{"body":"The Mutation type is a serialized enum that represents an operation that should be applied to update the UI. The variants roughly follow this set: enum Mutation { AppendChildren, AssignId, CreatePlaceholder, CreateTextNode, HydrateText, LoadTemplate, ReplaceWith, ReplacePlaceholder, InsertAfter, InsertBefore, SetAttribute, SetText, NewEventListener, RemoveEventListener, Remove, PushRoot,\n} The Dioxus diffing mechanism operates as a stack machine where the LoadTemplate , CreatePlaceholder , and CreateTextNode mutations pushes a new \"real\" DOM node onto the stack and AppendChildren , InsertAfter , InsertBefore , ReplacePlaceholder , and ReplaceWith all remove nodes from the stack.","breadcrumbs":"Custom Renderer » Mutations","id":"120","title":"Mutations"},"121":{"body":"Dioxus saves and loads elements with IDs. Inside the VirtualDOM, this is just tracked as as a u64. Whenever a CreateElement edit is generated during diffing, Dioxus increments its node counter and assigns that new element its current NodeCount. The RealDom is responsible for remembering this ID and pushing the correct node when id is used in a mutation. Dioxus reclaims the IDs of elements when removed. To stay in sync with Dioxus you can use a sparse Vec (Vec