Ver código fonte

wip: move to tokio/axum/etc

Jonathan Kelley 3 anos atrás
pai
commit
07efeda124

+ 1 - 3
.vscode/settings.json

@@ -1,3 +1 @@
-{
-  "rust-analyzer.inlayHints.enable": true
-}
+{}

+ 11 - 14
Cargo.toml

@@ -1,7 +1,7 @@
 [package]
 name = "dioxus-studio"
 version = "0.1.0"
-authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
+authors = ["Jonathan Kelley"]
 edition = "2018"
 description = "CLI tool for developing, testing, and publishing Dioxus apps"
 "license" = "MIT/Apache-2.0"
@@ -14,25 +14,22 @@ log = "0.4.13"
 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"] }
-tide = "0.16.0"
-fs_extra = "1.2.0"
 
+serde = "1"
+serde_json = "1"
+
+fs_extra = "1.2.0"
 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" }
+tui = { version = "0.16.0", features = ["crossterm"] }
+crossterm = "0.22.1"
+binary-install = "0.0.2"
+convert_case = "0.5.0"
+structopt = "0.3.25"
+cargo_metadata = "0.14.1"
 
 [[bin]]
-
 path = "src/main.rs"
 name = "dioxus"

+ 11 - 0
TODO.md

@@ -0,0 +1,11 @@
+
+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?

+ 38 - 21
src/builder.rs

@@ -3,26 +3,13 @@ use crate::{
     config::{CrateConfig, ExecutableType},
     error::{Error, Result},
 };
-use log::{info, warn};
 use std::{
     io::{Read, Write},
     process::Command,
 };
 use wasm_bindgen_cli_support::Bindgen;
 
-pub struct BuildConfig {}
-impl Into<BuildConfig> for BuildOptions {
-    fn into(self) -> BuildConfig {
-        BuildConfig {}
-    }
-}
-impl Default for BuildConfig {
-    fn default() -> Self {
-        Self {}
-    }
-}
-
-pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> 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
@@ -43,7 +30,7 @@ pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> {
     let t_start = std::time::Instant::now();
 
     // [1] Build the .wasm module
-    info!("Running build commands...");
+    log::info!("Running build commands...");
     let mut cmd = Command::new("cargo");
     cmd.current_dir(&crate_dir)
         .arg("build")
@@ -66,7 +53,7 @@ pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> {
     let output = child.wait()?;
 
     if output.success() {
-        info!("Build complete!");
+        log::info!("Build complete!");
     } else {
         log::error!("Build failed!");
         let mut reason = String::new();
@@ -87,12 +74,10 @@ pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> {
 
     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)),
     };
@@ -113,7 +98,7 @@ pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> {
 
     // [5] Generate the html file with the module name
     // TODO: support names via options
-    info!("Writing to '{:#?}' directory...", out_dir);
+    log::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())?;
 
@@ -121,7 +106,7 @@ pub fn build(config: &CrateConfig, _build_config: &BuildConfig) -> Result<()> {
     match fs_extra::dir::copy(static_dir, out_dir, &copy_options) {
         Ok(_) => {}
         Err(_e) => {
-            warn!("Error copying dir");
+            log::warn!("Error copying dir");
         }
     }
 
@@ -139,7 +124,7 @@ fn gen_page(module: &str) -> String {
     <meta charset="UTF-8" />
   </head>
   <body>
-    <div id="dioxusroot">
+    <div id="main">
     </div>
     <!-- Note the usage of `type=module` here as this is an ES6 module -->
     <script type="module">
@@ -153,3 +138,35 @@ fn gen_page(module: &str) -> String {
         module
     )
 }
+
+// use binary_install::{Cache, Download};
+
+// /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a
+// /// precompiled binary.
+// ///
+// /// Returns `Some` if a binary was found or it was successfully downloaded.
+// /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't
+// /// have precompiled binaries. Returns an error if we failed to download the
+// /// binary.
+// pub fn find_wasm_opt(
+//     cache: &Cache,
+//     install_permitted: bool,
+// ) -> Result<install::Status, failure::Error> {
+//     // First attempt to look up in PATH. If found assume it works.
+//     if let Ok(path) = which::which("wasm-opt") {
+//         PBAR.info(&format!("found wasm-opt at {:?}", path));
+
+//         match path.as_path().parent() {
+//             Some(path) => return Ok(install::Status::Found(Download::at(path))),
+//             None => {}
+//         }
+//     }
+
+//     let version = "version_78";
+//     Ok(install::download_prebuilt(
+//         &install::Tool::WasmOpt,
+//         cache,
+//         version,
+//         install_permitted,
+//     )?)
+// }

+ 4 - 0
src/cli.rs

@@ -90,6 +90,10 @@ pub struct TranslateOptions {
     /// an example in the crate
     #[argh(option, short = 't')]
     pub text: Option<String>,
+
+    /// whether or not to jump
+    #[argh(switch, short = 'c')]
+    pub component: bool,
 }
 /// 🛠 Translate some 3rd party template into rsx
 #[derive(FromArgs, PartialEq, Debug, Clone)]

+ 0 - 0
src/cmd/build.rs


+ 0 - 0
src/cmd/mod.rs


+ 0 - 0
src/cmd/serve.rs


+ 0 - 0
src/cmd/studio.rs


+ 0 - 0
src/watch.rs → src/cmd/watch.rs


+ 31 - 26
src/develop.rs → src/develop/develop.rs

@@ -1,37 +1,33 @@
-use crate::{builder::BuildConfig, cli::DevelopOptions, config::CrateConfig, error::Result};
+use crate::{cli::DevelopOptions, config::CrateConfig, 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::sync::atomic::AtomicBool;
 use std::sync::Arc;
-use std::time::Duration;
+use tide::http::mime::HTML;
+use tide::http::Mime;
 
-pub struct DevelopConfig {}
-impl Into<DevelopConfig> for DevelopOptions {
-    fn into(self) -> DevelopConfig {
-        DevelopConfig {}
-    }
+pub struct DevelopState {
+    //
+    reload_on_change: bool,
 }
 
-type ErrStatus = Arc<AtomicBool>;
-
-pub async fn start(config: &CrateConfig, _options: &DevelopConfig) -> Result<()> {
+pub async fn develop(options: DevelopOptions) -> Result<()> {
+    //
     log::info!("Starting development server 🚀");
+    let mut cfg = CrateConfig::new()?;
+    cfg.with_develop_options(&options);
 
-    let CrateConfig { out_dir, .. } = config;
+    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.clone(), is_err.clone()));
-
-    let watcher = async_std::task::spawn(watch_directory(config.clone(), is_err.clone()));
+    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),
@@ -70,10 +66,8 @@ async fn watch_directory(config: CrateConfig, is_err: ErrStatus) -> Result<()> {
         Err(e) => log::warn!("Failed to watch examples dir, {:?}", e),
     }
 
-    let build_config = BuildConfig::default();
-
     'run: loop {
-        match crate::builder::build(&config, &build_config) {
+        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;
@@ -100,6 +94,9 @@ async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> {
     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("/")
@@ -108,22 +105,27 @@ async fn launch_server(outdir: PathBuf, is_err: ErrStatus) -> Result<()> {
             let state = req.state();
 
             match state.is_err.load(std::sync::atomic::Ordering::Relaxed) {
-                true => Ok(tide::Body::from_string(format!(
-                    include_str!("./err.html"),
-                    err = "_"
-                ))),
+                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!("0.0.0.0:{}", port);
     let serve_addr = format!("127.0.0.1:{}", port);
 
-    info!("App available at http://{}", serve_addr);
+    info!("App available at http://{}/", serve_addr);
     app.listen(serve_addr).await?;
     Ok(())
 }
@@ -136,6 +138,9 @@ struct ServerState {
     serv_path: PathBuf,
     is_err: ErrStatus,
 }
+
+type ErrStatus = Arc<AtomicBool>;
+
 impl ServerState {
     fn new(serv_path: PathBuf, is_err: ErrStatus) -> Self {
         Self { serv_path, is_err }

+ 0 - 0
src/develop/draw.rs


+ 0 - 0
src/develop/events.rs


+ 48 - 78
src/studio.rs → src/develop/studio.rs

@@ -1,11 +1,23 @@
 //! It's better to store all the configuration in one spot
-//!
-use tui_template::tuiapp::TuiApp;
+
+use tui::{
+    backend::{Backend, CrosstermBackend},
+    layout::{Constraint, Direction, Layout, Rect},
+    style::{Color, Modifier, Style},
+    symbols,
+    text::{Span, Spans},
+    widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle},
+    widgets::{
+        Axis, BarChart, Block, BorderType, Borders, Cell, Chart, Dataset, Gauge, LineGauge, List,
+        ListItem, Paragraph, Row, Sparkline, Table, Tabs, Wrap,
+    },
+    Frame, Terminal,
+};
 
 use crate::*;
 use std::{any::Any, io::Write, path::PathBuf, process::Command};
 
-pub struct Studio {
+pub struct Cfg {
     command: LaunchOptions,
     headless: bool,
     example: Option<String>,
@@ -15,87 +27,45 @@ pub struct Studio {
     template: Option<String>,
     translate_file: Option<String>,
     crate_config: Option<CrateConfig>,
+    should_quit: bool,
 }
 
-impl Studio {
-    pub fn new(command: LaunchOptions) -> Self {
-        let headless = true;
-        let release = false;
-        let example = None;
-        let outdir = None;
-        let hydrate = None;
-        let template = None;
-        let translate_file = None;
-        let crate_config = None;
-
-        match command.command {
-            LaunchCommand::Translate(_) => todo!(),
-            LaunchCommand::Develop(_) => todo!(),
-            LaunchCommand::Build(_) => todo!(),
-            LaunchCommand::Test(_) => todo!(),
-            LaunchCommand::Publish(_) => todo!(),
-            LaunchCommand::Studio(StudioOptions { .. }) => {
-                //
-            }
-        };
-
-        Self {
-            command,
-            headless,
-            example,
-            outdir,
-            release,
-            hydrate,
-            template,
-            translate_file,
-            crate_config,
-        }
-    }
-
-    pub async fn start(self) -> Result<()> {
-        match self.command.command {
-            LaunchCommand::Develop(_) => todo!(),
-            LaunchCommand::Build(_) => todo!(),
-            LaunchCommand::Translate(_) => todo!(),
-            LaunchCommand::Test(_) => todo!(),
-            LaunchCommand::Publish(_) => todo!(),
-            LaunchCommand::Studio(_) => self.launch_studio().await?,
-        }
-        Ok(())
+pub async fn start(options: DevelopOptions) -> Result<()> {
+    let mut state = Cfg {
+        command: todo!(),
+        headless: todo!(),
+        example: todo!(),
+        outdir: todo!(),
+        release: todo!(),
+        hydrate: todo!(),
+        template: todo!(),
+        translate_file: todo!(),
+        crate_config: todo!(),
+        should_quit: false,
+    };
+
+    crossterm::terminal::enable_raw_mode()?;
+
+    let backend = CrosstermBackend::new(std::io::stdout());
+    let mut terminal = Terminal::new(backend).unwrap();
+
+    // Setup input handling
+    // let (tx, rx) = futures::channel::mpsc::unbounded();
+    let tick_rate = std::time::Duration::from_millis(100);
+
+    let mut prev_time = std::time::Instant::now();
+    while !state.should_quit {
+        let next_time = prev_time + tick_rate;
+        let now = std::time::Instant::now();
+
+        let diff = next_time - std::time::Instant::now();
     }
 
-    pub async fn launch_studio(mut self) -> Result<()> {
-        let task = async_std::task::spawn_blocking(|| async move {
-            let mut app = TuiStudio {
-                cfg: self,
-                hooks: vec![],
-                hook_idx: 0,
-            };
-            app.launch(250).expect("tui app crashed :(");
-        });
-        let r = task.await.await;
-
-        Ok(())
-    }
+    Ok(())
 }
 
-use tui::{
-    backend::Backend,
-    layout::{Constraint, Direction, Layout, Rect},
-    style::{Color, Modifier, Style},
-    symbols,
-    text::{Span, Spans},
-    widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle},
-    widgets::{
-        Axis, BarChart, Block, BorderType, Borders, Cell, Chart, Dataset, Gauge, LineGauge, List,
-        ListItem, Paragraph, Row, Sparkline, Table, Tabs, Wrap,
-    },
-    Frame,
-};
-
 struct TuiStudio {
-    cfg: Studio,
-
+    cfg: Cfg,
     hook_idx: usize,
     hooks: Vec<Box<dyn Any>>,
 }
@@ -112,7 +82,7 @@ impl TuiStudio {
     }
 }
 
-impl TuiApp for TuiStudio {
+impl TuiStudio {
     fn event_handler(&self, action: crossterm::event::Event) -> anyhow::Result<()> {
         match action {
             crossterm::event::Event::Key(_) => {}

+ 0 - 0
src/helpers/extract_svgs.rs


+ 181 - 0
src/helpers/to_component.rs

@@ -0,0 +1,181 @@
+//! Intelligently converts html to rsx with appropraite transformations and extractions.
+//!
+//! - [*] Creates a component
+//! - [ ] Extracts svgs
+//! - [ ] Attempts to extract lists
+
+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<ComponentRenderer> {
+    Ok(ComponentRenderer {
+        dom: Dom::parse(html)?,
+        icon_index: 0,
+    })
+}
+
+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, "\",")?;
+    }
+    write!(f, "\n")?;
+
+    // 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();
+}

+ 33 - 6
src/translate.rs → src/helpers/translate.rs

@@ -1,4 +1,4 @@
-use std::fmt::{Debug, Display, Formatter};
+use std::fmt::{Display, Formatter};
 
 use anyhow::Result;
 
@@ -33,13 +33,25 @@ impl Display for RsxRenderer {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         if self.as_call {
             writeln!(f, r##"use dioxus::prelude::*;"##)?;
-            writeln!(f, r##"const Component: FC<()> = |cx| cx.render(rsx!{{"##)?;
+            writeln!(
+                f,
+                r##"
+fn component(cx: Scope) -> Element {{
+    cx.render(rsx!(
+"##
+            )?;
         }
         for child in &self.dom.children {
             render_child(f, child, 1)?;
         }
         if self.as_call {
-            write!(f, r##"}});"##)?;
+            write!(
+                f,
+                r##"
+    )
+)            
+            "##
+            )?;
         }
         Ok(())
     }
@@ -74,9 +86,24 @@ fn render_child(f: &mut Formatter<'_>, child: &Node, il: u32) -> std::fmt::Resul
 
             for (name, value) in &el.attributes {
                 write_tabs(f, il + 1)?;
-                match value {
-                    Some(val) => writeln!(f, "{}: \"{}\",", name, val)?,
-                    None => writeln!(f, "{}: \"\",", name)?,
+
+                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)?,
+                    }
                 }
             }
 

+ 0 - 21
src/lib.rs

@@ -1,21 +0,0 @@
-mod builder;
-mod cargo;
-mod cli;
-mod config;
-mod develop;
-mod error;
-mod logging;
-mod studio;
-mod translate;
-mod watch;
-
-pub use builder::*;
-pub use cargo::*;
-pub use cli::*;
-pub use config::*;
-pub use develop::*;
-pub use error::*;
-pub use logging::*;
-pub use studio::*;
-pub use translate::*;
-pub use watch::*;

+ 0 - 12
src/logging.rs

@@ -1,5 +1,4 @@
 use fern::colors::{Color, ColoredLevelConfig};
-use log::debug;
 
 pub fn set_up_logging() {
     // configure colors for the whole line
@@ -29,18 +28,7 @@ pub fn set_up_logging() {
                 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();

+ 89 - 4
src/main.rs

@@ -1,12 +1,97 @@
-use dioxus_studio::{set_up_logging, LaunchCommand, LaunchOptions};
+mod builder;
+mod cargo;
+mod cli;
+mod config;
+mod error;
+mod logging;
+mod helpers {
+    pub mod extract_svgs;
+    pub mod to_component;
+    pub mod translate;
+}
+
+mod watch;
+mod develop {
+    pub mod develop;
+    pub mod draw;
+    pub mod events;
+    pub mod studio;
+}
+
+use std::path::PathBuf;
+use structopt::StructOpt;
 
 #[async_std::main]
-async fn main() -> dioxus_studio::Result<()> {
+async fn main() -> Result<()> {
     set_up_logging();
+    let args = Args::from_args();
+
+    match args.command {
+        LaunchCommand::Develop(cfg) => {
+            develop::develop::develop(cfg).await?;
+        }
+        // LaunchCommand::Develop(cfg) => develop::studio::start(cfg).await?,
+        LaunchCommand::Build(opts) => {
+            let mut cfg = CrateConfig::new()?;
+            cfg.with_build_options(&opts);
+            builder::build(&cfg)?;
+        }
 
-    let opts: LaunchOptions = argh::from_env();
+        LaunchCommand::Translate(cfg) => {
+            let TranslateOptions {
+                file,
+                text,
+                component,
+            } = cfg;
 
-    dioxus_studio::Studio::new(opts).start().await?;
+            match component {
+                true => {
+                    let f = helpers::to_component::convert_html_to_component(&text.unwrap())?;
+                    println!("{}", f);
+                }
+                false => {
+                    let renderer = match (file, text) {
+                        (None, Some(text)) => translate::translate_from_html_to_rsx(&text, false)?,
+                        (Some(file), None) => translate::translate_from_html_file(&file)?,
+                        _ => panic!("Must select either file or text - not both or none!"),
+                    };
+
+                    println!("{}", renderer);
+                }
+            }
+        }
+        _ => {
+            todo!("Those commands are not yet supported");
+        }
+    }
 
     Ok(())
 }
+
+/// Build, bundle & ship your Rust WASM application to the web.
+#[derive(StructOpt)]
+#[structopt(name = "trunk")]
+struct Args {
+    #[structopt(subcommand)]
+    command: TrunkSubcommands,
+    /// Path to the Trunk config file [default: Trunk.toml]
+    #[structopt(long, parse(from_os_str), env = "TRUNK_CONFIG")]
+    pub config: Option<PathBuf>,
+    /// Enable verbose logging.
+    #[structopt(short)]
+    pub v: bool,
+}
+
+#[derive(StructOpt)]
+enum TrunkSubcommands {
+    /// Build the Rust WASM app and all of its assets.
+    Build(cmd::build::Build),
+    /// Build & watch the Rust WASM app and all of its assets.
+    Watch(cmd::watch::Watch),
+    /// Build, watch & serve the Rust WASM app and all of its assets.
+    Serve(cmd::serve::Serve),
+    /// Clean output artifacts.
+    Clean(cmd::clean::Clean),
+    /// Trunk config controls.
+    Config(cmd::config::Config),
+}

+ 30 - 0
tests/svg.html

@@ -0,0 +1,30 @@
+<div>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+    <svg class="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
+    <path
+        fill-rule="evenodd"
+        d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+        clip-rule="evenodd"
+    />
+    </svg>
+</div>