Skip to content

Commit

Permalink
Added save functionality for the web version
Browse files Browse the repository at this point in the history
  • Loading branch information
margual56 committed Apr 2, 2023
1 parent 4d6fac8 commit 17c351a
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 43 deletions.
51 changes: 51 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ env_logger = "0.10.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"
tracing-wasm = "0.2"
wasm-bindgen = "0.2.84"
wasm-bindgen-futures = "0.4.33"
futures = "0.3"


[profile.release]
Expand Down
9 changes: 9 additions & 0 deletions assets/save_file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function saveFile(filename, content) {
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!-- Disable zooming: -->
Expand All @@ -20,6 +20,7 @@
<link data-trunk rel="copy-file" href="assets/sw.js" />
<link data-trunk rel="copy-file" href="assets/manifest.json" />
<link data-trunk rel="copy-file" href="assets/icon.png" />
<link data-trunk rel="copy-file" href="assets/save_file.js" />


<link rel="manifest" href="manifest.json">
Expand Down
12 changes: 2 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use {
std::{fs, io, path::PathBuf},
turing_lib::Rule,
turing_machine::windows::ErrorWindow,
turing_lib::TuringMachine,
};

use turing_lib::TuringMachine;
use turing_machine::MyApp;

#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -68,20 +68,12 @@ fn main() {
// Redirect tracing to console.log and friends:
tracing_wasm::set_as_global_default();

let tm = match TuringMachine::new(UNPARSED_FILE) {
Ok(t) => t,
Err(_e) => {
//handle_error(e, file);
std::process::exit(1);
}
};

let web_options = eframe::WebOptions::default();
wasm_bindgen_futures::spawn_local(async {
eframe::start_web(
"the_canvas_id", // hardcode it
web_options,
Box::new(|cc| Box::new(MyApp::new(tm, cc))),
Box::new(|cc| Box::new(MyApp::new(&None, cc).unwrap())),
)
.await
.expect("failed to start eframe");
Expand Down
74 changes: 51 additions & 23 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,21 @@ use log::{debug, error, info, trace, warn};
use turing_lib::TuringMachine;
use turing_lib::{Rule, TuringOutput};

#[cfg(target_arch = "wasm32")]
use {
wasm_bindgen::prelude::wasm_bindgen,
std::sync::{Arc, Mutex},
};

const DEFAULT_CODE: &str = include_str!("../Examples/Example1.tm");

// Import the saveFile function
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(module = "/dist/.stage/save_file.js")]
extern "C" {
fn saveFile(filename: &str, content: &str);
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Language {
English,
Expand Down Expand Up @@ -348,19 +361,9 @@ impl MyApp {
fn save_file(&mut self) {
#[cfg(target_family = "wasm")]
{
// Spawn dialog on main thread
let task = rfd::AsyncFileDialog::new().save_file();

// Await somewhere else
wasm_bindgen_futures::spawn_local(async move {
let file = task.await;

if let Some(f) = file {
// If you care about wasm support you just read() the file
f.write_all(self.code.as_bytes()).await;
self.file = Some(f);
}
});
let filename = "exercise.tm"; // Replace with your desired file name
let content = &self.code;
saveFile(filename, content);
}

#[cfg(not(target_family = "wasm"))]
Expand Down Expand Up @@ -389,6 +392,24 @@ impl MyApp {
}
}

#[cfg(target_family = "wasm")]
fn clone_for_load_file(&self) -> Self {
MyApp {
tm: self.tm.clone(),
code: self.code.clone(),
error: self.error.clone(),
about_window: None,
debug_window: None,
infinite_loop_window: None,
book_window: None,
lang: self.lang.clone(),

file: self.file.clone(),
autosave: self.autosave.clone(),
saved_feedback: None,
}
}

/// This method loads the code from an associated file, or spawns a dialog to select a file and then
/// loads the code from it. The method handles both WebAssembly and non-WebAssembly targets.
///
Expand All @@ -408,34 +429,41 @@ impl MyApp {
fn load_file(&mut self) {
#[cfg(target_family = "wasm")]
{
// Spawn dialog on main thread
let task = rfd::AsyncFileDialog::new().pick_file();

// Wrap MyApp in Arc<Mutex> with the custom clone method
let shared_self = Arc::new(Mutex::new(self.clone_for_load_file()));

// Await somewhere else
wasm_bindgen_futures::spawn_local(async move {
let load_future = async move {
let file = task.await;

if let Some(file) = file {
if let Some(f) = file {
// If you care about wasm support you just read() the file
let buffer = file.read().await;
let buffer = f.read().await;
match String::from_utf8(buffer) {
Ok(s) => {
self.tm = match self.tm.restart(&s) {
let mut borrowed_self = shared_self.lock().unwrap();

borrowed_self.tm = match borrowed_self.tm.restart(&s) {
Ok(t) => {
self.error = None;
borrowed_self.error = None;
t
}
Err(e) => {
self.error = Some(e);
self.tm.clone()
borrowed_self.error = Some(e);
borrowed_self.tm.clone()
}
};
self.code = s;
borrowed_self.code = s;
}
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
}
}
});
};

// Spawn future without boxing it
wasm_bindgen_futures::spawn_local(load_future);
}

#[cfg(not(target_family = "wasm"))]
Expand Down
14 changes: 6 additions & 8 deletions src/windows/book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,16 @@ impl BookWindow {
Exercise::new(
"Exercise 1",
include_bytes!("../../assets/ui/exercise1/cover.png"),
String::from_utf8(
include_bytes!("../../assets/ui/exercise1/code.tm").to_vec(),
)
.unwrap(),
String::from(
include_str!("../../assets/ui/exercise1/code.tm"),
),
),
Exercise::new(
"Exercise 2",
include_bytes!("../../assets/ui/exercise2/cover.png"),
String::from_utf8(
include_bytes!("../../assets/ui/exercise2/code.tm").to_vec(),
)
.unwrap(),
String::from(
include_str!("../../assets/ui/exercise2/code.tm"),
),
),
],
),
Expand Down
2 changes: 1 addition & 1 deletion src/windows/infinite_loop_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::SecondaryWindow;
use eframe::egui::{self, RichText, Window};
use internationalization::t;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct InfiniteLoopWindow {
lang: String,
}
Expand Down

0 comments on commit 17c351a

Please sign in to comment.