diff --git a/src/components/Playground.tsx b/src/components/Playground.tsx index cc9b458..a1e1023 100644 --- a/src/components/Playground.tsx +++ b/src/components/Playground.tsx @@ -1,6 +1,8 @@ import { useEffect, useState } from "react"; import { useMonaco, type Monaco } from "@monaco-editor/react"; import { useImmer, type Updater } from "use-immer"; +import ThemeProvider from "@mui/material/styles/ThemeProvider"; +import ErrorDisplay from "./playground/ErrorDisplay"; import FileView from "./playground/FileView"; import Editor from "./playground/Editor"; import Header from "./playground/Header"; @@ -16,7 +18,6 @@ import "@styles/playground.scss"; import mainFileContent from "@assets/playground/main.shu?raw"; import packTomlContent from "@assets/playground/pack.toml?raw"; -import ThemeProvider from "@mui/material/styles/ThemeProvider"; const FILE_STORAGE_KEY = "playground-files"; const DEFAULT_FILES = { @@ -40,6 +41,18 @@ const DEFAULT_FILES = { }; export default function Playground({ lang }: { lang: PlaygroundLang }) { + const [errorMsg, setErrorMsg] = useState(null); + + useEffect(() => { + (window as any).playground = { + showError: (message: string) => { + if (message.length > 0) { + setErrorMsg(message); + } + }, + }; + }, []); + initWasm().catch((err) => { console.error(err); }); @@ -63,8 +76,6 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) { }, } as Directory; loadFiles(monaco, updateRootDir, withRoot); - } else { - alert("Compilation failed"); } } else { console.error("monaco has not loaded"); @@ -79,8 +90,6 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) { a.href = data; a.download = "shulkerscript-pack.zip"; a.click(); - } else { - alert("Compilation failed"); } } else { console.error("monaco has not loaded"); @@ -167,6 +176,7 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) { marginTop: "0.5cm", }} > +
void; +}) { + return ( + setError(null)}> + Error during compilation! + +
+ +
+
+ + + +
+ ); +} diff --git a/src/wasm/webcompiler/Cargo.toml b/src/wasm/webcompiler/Cargo.toml index c4f0646..5aaa798 100644 --- a/src/wasm/webcompiler/Cargo.toml +++ b/src/wasm/webcompiler/Cargo.toml @@ -17,3 +17,5 @@ anyhow = "1.0.86" zip = { version = "2.1.3", default-features = false, features = ["deflate"] } base64 = "0.22.1" console_error_panic_hook = "0.1.7" +ansi-to-html = "0.2.1" +colored = "2.1.0" diff --git a/src/wasm/webcompiler/src/lib.rs b/src/wasm/webcompiler/src/lib.rs index 1416dc6..afc3543 100644 --- a/src/wasm/webcompiler/src/lib.rs +++ b/src/wasm/webcompiler/src/lib.rs @@ -1,8 +1,8 @@ use std::{ - cell::Cell, fmt::Display, io::{Cursor, Write}, path::PathBuf, + sync::Mutex, }; use anyhow::Result; @@ -24,6 +24,9 @@ extern "C" { fn log(s: &str); #[wasm_bindgen(js_namespace = console, js_name = error)] fn log_err(s: &str); + + #[wasm_bindgen(js_namespace = ["window", "playground"], js_name = showError)] + fn show_err(s: &str); } /// Compiles the given directory into datapack files. @@ -57,38 +60,38 @@ pub fn compile_zip(root_dir: JsValue) -> Option { // write each file to the zip archive for (path, file) in virtual_files { - writer - .start_file(path, SimpleFileOptions::default()) - .unwrap(); + writer.start_file(path, SimpleFileOptions::default()).ok()?; match file { VFile::Text(text) => { - writer.write_all(text.as_bytes()).unwrap(); + writer.write_all(text.as_bytes()).ok()?; } VFile::Binary(data) => { - writer.write_all(data).unwrap(); + writer.write_all(data).ok()?; } } } writer.set_comment("Data pack created with Shulkerscript web compiler"); - writer.finish().unwrap(); + writer.finish().ok()?; Some(BASE64_STANDARD.encode(buffer.into_inner())) } fn _compile(root_dir: &VFolder) -> Result { + colored::control::set_override(true); let printer = Printer::new(); - util::compile(&printer, root_dir, &get_script_paths(root_dir)) + let res = util::compile(&printer, root_dir, &get_script_paths(root_dir)); + printer.display(); + res } struct Printer { - printed: Cell, + queue: Mutex>, } impl Handler for Printer { fn receive>(&self, error: E) { - log_err(&error.into().to_string()); - self.printed.set(true); + self.queue.lock().unwrap().push(format!("{}", error.into())); } fn has_received(&self) -> bool { @@ -99,12 +102,23 @@ impl Printer { /// Creates a new [`Printer`]. fn new() -> Self { Self { - printed: Cell::new(false), + queue: Mutex::new(Vec::new()), } } + fn display(self) { + let queue = self + .queue + .into_inner() + .unwrap() + .into_iter() + .map(|el| ansi_to_html::convert(&el).unwrap()) + .collect::>(); + show_err(&queue.join("\n\n")); + } + fn has_printed(&self) -> bool { - self.printed.get() + !self.queue.lock().unwrap().is_empty() } }