1
0
Эх сурвалжийг харах

WIP: expose pipe for desktop

Evan Almloff 3 жил өмнө
parent
commit
0079f7d18b

+ 1 - 1
Cargo.toml

@@ -49,7 +49,7 @@ desktop = ["dioxus-desktop"]
 router = ["dioxus-router"]
 tui = ["dioxus-tui"]
 liveview = ["dioxus-liveview"]
-hot_reload = ["dioxus-core-macro/hot_reload", "dioxus-rsx-interpreter"]
+hot_reload = ["dioxus-core-macro/hot_reload", "dioxus-rsx-interpreter", "dioxus-desktop?/hot_reload"]
 native-core = ["dioxus-native-core", "dioxus-native-core-macro"]
 
 

+ 1 - 86
examples/hot_reload.rs

@@ -5,92 +5,7 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
-    let rsx_code = use_state(&cx, || {
-        r##"div {
-            width: "100%",
-            height: "500px",
-            onclick: move |_| {
-                count.modify(|count| *count + 10);
-            },
-
-            p {
-                "High-Five counter: {count.to_string():?}",
-            }
-
-            div {
-                width: "{count}px",
-                height: "10px",
-                background_color: "red",
-            }
-
-            Comp {
-                color: "#083289"
-            }
-
-            Comp {
-                color: "green"
-            }
-
-            {
-                (0..10).map(|i| {
-                    cx.render(rsx!{p {"{i}"}})
-                })
-            }
-        }"##
-        .to_string()
-    });
-    let submitted_rsx_code = use_state(&cx, || None);
-
-    cx.render(rsx! {
-        div {
-            display: "flex",
-            flex_direction: "row",
-            width: "100%",
-            height: "100%",
-            Editable{
-               current_code: submitted_rsx_code.get().clone(),
-            },
-
-            textarea {
-                width: "50em",
-                height: "50em",
-                value: rsx_code,
-                oninput: move |evt| {
-                    rsx_code.set(evt.value.clone());
-                },
-            }
-
-            button {
-                height: "100%",
-                width: "10%",
-                onclick: move |_|{
-                   submitted_rsx_code.set(Some(rsx_code.get().clone()));
-                },
-                "submit"
-            }
-        }
-    })
-}
-
-#[derive(PartialEq, Props)]
-struct EditableProps {
-    #[props(!optional)]
-    current_code: Option<String>,
-}
-
-fn Editable(cx: Scope<EditableProps>) -> Element {
     let count = use_state(&cx, || 170);
-    if let Some(code) = cx.props.current_code.as_ref() {
-        let rsx_index: RsxContext = cx.consume_context().unwrap();
-        rsx_index.insert(
-            CodeLocation {
-                file: r"examples\hot_reload.rs".to_string(),
-                line: 94,
-                column: 15,
-            },
-            code.clone(),
-        );
-    }
     cx.render(rsx! {
          div {
             width: "100%",
@@ -98,7 +13,7 @@ fn Editable(cx: Scope<EditableProps>) -> Element {
             onclick: move |_| {
                 count.modify(|count| *count + 10);
             },
-
+            p{"{__line_num:?}"}
             p {
                 "High-Five counter: {count.to_string():?}",
             }

+ 1 - 1
packages/core-macro/src/lib.rs

@@ -186,7 +186,7 @@ pub fn rsx(s: TokenStream) -> TokenStream {
         Ok(body) => {
             #[cfg(feature = "hot_reload")]
             {
-                use dioxus_rsx_interperter::captuered_context::CapturedContextBuilder;
+                use dioxus_rsx_interpreter::captuered_context::CapturedContextBuilder;
 
                 match CapturedContextBuilder::from_call_body(body) {
                     Ok(captured) => {

+ 4 - 0
packages/desktop/Cargo.toml

@@ -15,6 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
 dioxus-core = { path = "../core", version = "^0.2.1", features = ["serialize"] }
 dioxus-html = { path = "../html", features = ["serialize"], version = "^0.2.1" }
 dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1" }
+dioxus-rsx-interpreter = { path = "../rsx_interpreter", optional = true }
 
 serde = "1.0.136"
 serde_json = "1.0.79"
@@ -32,6 +33,8 @@ webbrowser = "0.7.1"
 mime_guess = "2.0.3"
 dunce = "1.0.2"
 
+interprocess = { version = "1.1.1", optional = true }
+
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.9.3"
 
@@ -41,6 +44,7 @@ tokio_runtime = ["tokio"]
 fullscreen = ["wry/fullscreen"]
 transparent = ["wry/transparent"]
 tray = ["wry/tray"]
+hot_reload = ["dioxus-rsx-interpreter", "interprocess"]
 
 [dev-dependencies]
 dioxus-core-macro = { path = "../core-macro" }

+ 91 - 0
packages/desktop/src/controller.rs

@@ -1,4 +1,5 @@
 use crate::desktop_context::{DesktopContext, UserWindowEvent};
+
 use dioxus_core::*;
 use std::{
     collections::HashMap,
@@ -49,6 +50,96 @@ impl DesktopController {
 
                 dom.base_scope().provide_context(window_context);
 
+                // allow other proccesses to send the new rsx text to the @dioxus ipc channel
+                #[cfg(feature = "hot_reload")]
+                {
+                    use dioxus_rsx_interpreter::{
+                        error::Error, ErrorHandler, RsxContext, RsxData, SetRsxMessage,
+                    };
+                    use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
+                    use std::io::{BufRead, BufReader, Write};
+                    use std::time::Duration;
+
+                    fn handle_error(
+                        connection: std::io::Result<LocalSocketStream>,
+                    ) -> Option<LocalSocketStream> {
+                        connection
+                            .map_err(|error| eprintln!("Incoming connection failed: {}", error))
+                            .ok()
+                    }
+
+                    let latest_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
+                        Arc::new(Mutex::new(None));
+                    let latest_connection_handle = latest_connection.clone();
+                    let latest_connection_handle2 = latest_connection.clone();
+
+                    struct DesktopErrorHandler {
+                        latest_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>>,
+                    }
+                    impl ErrorHandler for DesktopErrorHandler {
+                        fn handle_error(&self, err: Error) {
+                            println!("reporting err: {err:?}");
+                            if let Some(conn) = &mut *self.latest_connection.lock().unwrap() {
+                                if let Error::RecompileRequiredError(reason) = err {
+                                    conn.get_mut()
+                                        .write_all(
+                                            (serde_json::to_string(&reason).unwrap() + "\n")
+                                                .as_bytes(),
+                                        )
+                                        .unwrap();
+                                    println!("sending error");
+                                }
+                            }
+                        }
+                    }
+
+                    let context = dom
+                        .base_scope()
+                        .provide_root_context(RsxContext::new(RsxData {
+                            hm: HashMap::new(),
+                            error_handler: Box::new(DesktopErrorHandler {
+                                latest_connection: latest_connection_handle,
+                            }),
+                        }));
+
+                    std::thread::spawn(move || {
+                        if let Ok(listener) = LocalSocketListener::bind("@dioxus") {
+                            for conn in listener.incoming().filter_map(handle_error) {
+                                // conn.set_nonblocking(true);
+                                println!("connected");
+                                *latest_connection_handle2.lock().unwrap() =
+                                    Some(BufReader::new(conn));
+                            }
+                        }
+                    });
+
+                    std::thread::spawn(move || {
+                        loop {
+                            if let Some(conn) = &mut *latest_connection.lock().unwrap() {
+                                let mut buf = String::new();
+                                println!("reading");
+                                match conn.read_line(&mut buf) {
+                                    Ok(_) => {
+                                        println!("read");
+                                        let message: SetRsxMessage =
+                                            serde_json::from_str(&buf).unwrap();
+                                        println!("{:?}", message.location);
+                                        context.insert(message.location, message.new_text);
+                                    }
+                                    Err(err) => {
+                                        if err.kind() != std::io::ErrorKind::WouldBlock {
+                                            println!("{err}");
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                            // give the error handler time to take the mutex
+                            std::thread::sleep(Duration::from_millis(10));
+                        }
+                    });
+                }
+
                 let edits = dom.rebuild();
 
                 edit_queue

+ 19 - 4
packages/rsx_interpreter/src/lib.rs

@@ -1,5 +1,4 @@
 use dioxus_core::{Component, Element, LazyNodes, Scope, VNode};
-use dioxus_hooks::*;
 use error::Error;
 use interperter::build;
 use serde::{Deserialize, Serialize};
@@ -11,7 +10,7 @@ use syn::parse_str;
 mod attributes;
 pub mod captuered_context;
 mod elements;
-mod error;
+pub mod error;
 mod interperter;
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
@@ -50,7 +49,7 @@ pub struct RsxContext {
 
 pub struct RsxData {
     pub hm: HashMap<CodeLocation, String>,
-    error_handle: Box<dyn FnMut(Error)>,
+    pub error_handler: Box<dyn ErrorHandler + Send + Sync>,
 }
 
 impl std::fmt::Debug for RsxData {
@@ -60,6 +59,12 @@ impl std::fmt::Debug for RsxData {
 }
 
 impl RsxContext {
+    pub fn new(data: RsxData) -> Self {
+        Self {
+            data: Arc::new(RwLock::new(data)),
+        }
+    }
+
     pub fn insert(&self, loc: CodeLocation, text: String) {
         self.data.write().unwrap().hm.insert(loc, text);
     }
@@ -69,6 +74,16 @@ impl RsxContext {
     }
 
     pub fn report_error(&self, error: Error) {
-        (self.data.write().unwrap().error_handle)(error)
+        self.data.write().unwrap().error_handler.handle_error(error)
     }
 }
+
+pub trait ErrorHandler {
+    fn handle_error(&self, err: Error);
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct SetRsxMessage {
+    pub location: CodeLocation,
+    pub new_text: String,
+}

+ 4 - 1
src/lib.rs

@@ -46,6 +46,9 @@ pub mod events {
 
 pub use dioxus_rsx as rsx;
 
+#[cfg(feature = "hot_reload")]
+pub use dioxus_rsx_interpreter as rsx_interpreter;
+
 pub mod prelude {
     pub use crate::hooks::*;
     pub use dioxus_core::prelude::*;
@@ -60,7 +63,7 @@ pub mod prelude {
     pub use fermi::{use_atom_ref, use_init_atom_root, use_read, use_set, Atom, AtomRef};
 
     #[cfg(feature = "hot_reload")]
-    pub use dioxus_rsx_interperter::{
+    pub use dioxus_rsx_interpreter::{
         captuered_context::{CapturedContext, FormattedArg, IfmtArgs},
         get_line_num, interpert_rsx, CodeLocation, RsxContext,
     };