show compile errors in ui
This commit is contained in:
parent
a623308496
commit
664dbf4f6b
|
@ -1,6 +1,8 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useMonaco, type Monaco } from "@monaco-editor/react";
|
import { useMonaco, type Monaco } from "@monaco-editor/react";
|
||||||
import { useImmer, type Updater } from "use-immer";
|
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 FileView from "./playground/FileView";
|
||||||
import Editor from "./playground/Editor";
|
import Editor from "./playground/Editor";
|
||||||
import Header from "./playground/Header";
|
import Header from "./playground/Header";
|
||||||
|
@ -16,7 +18,6 @@ import "@styles/playground.scss";
|
||||||
|
|
||||||
import mainFileContent from "@assets/playground/main.shu?raw";
|
import mainFileContent from "@assets/playground/main.shu?raw";
|
||||||
import packTomlContent from "@assets/playground/pack.toml?raw";
|
import packTomlContent from "@assets/playground/pack.toml?raw";
|
||||||
import ThemeProvider from "@mui/material/styles/ThemeProvider";
|
|
||||||
|
|
||||||
const FILE_STORAGE_KEY = "playground-files";
|
const FILE_STORAGE_KEY = "playground-files";
|
||||||
const DEFAULT_FILES = {
|
const DEFAULT_FILES = {
|
||||||
|
@ -40,6 +41,18 @@ const DEFAULT_FILES = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Playground({ lang }: { lang: PlaygroundLang }) {
|
export default function Playground({ lang }: { lang: PlaygroundLang }) {
|
||||||
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(window as any).playground = {
|
||||||
|
showError: (message: string) => {
|
||||||
|
if (message.length > 0) {
|
||||||
|
setErrorMsg(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
initWasm().catch((err) => {
|
initWasm().catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
@ -63,8 +76,6 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) {
|
||||||
},
|
},
|
||||||
} as Directory;
|
} as Directory;
|
||||||
loadFiles(monaco, updateRootDir, withRoot);
|
loadFiles(monaco, updateRootDir, withRoot);
|
||||||
} else {
|
|
||||||
alert("Compilation failed");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("monaco has not loaded");
|
console.error("monaco has not loaded");
|
||||||
|
@ -79,8 +90,6 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) {
|
||||||
a.href = data;
|
a.href = data;
|
||||||
a.download = "shulkerscript-pack.zip";
|
a.download = "shulkerscript-pack.zip";
|
||||||
a.click();
|
a.click();
|
||||||
} else {
|
|
||||||
alert("Compilation failed");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("monaco has not loaded");
|
console.error("monaco has not loaded");
|
||||||
|
@ -167,6 +176,7 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) {
|
||||||
marginTop: "0.5cm",
|
marginTop: "0.5cm",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<ErrorDisplay error={errorMsg} setError={setErrorMsg} />
|
||||||
<Header
|
<Header
|
||||||
lang={lang.header}
|
lang={lang.header}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Dialog from "@mui/material/Dialog";
|
||||||
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
|
|
||||||
|
export default function ErrorDisplay({
|
||||||
|
error,
|
||||||
|
setError,
|
||||||
|
}: {
|
||||||
|
error: string | null;
|
||||||
|
setError: (error: string | null) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Dialog open={error !== null} onClose={() => setError(null)}>
|
||||||
|
<DialogTitle>Error during compilation!</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: "black",
|
||||||
|
padding: "15px",
|
||||||
|
borderRadius: "15px",
|
||||||
|
fontSize: "1.2em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<code
|
||||||
|
style={{
|
||||||
|
whiteSpace: "break-spaces",
|
||||||
|
fontFamily: "monospace",
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: error ?? "" }}
|
||||||
|
></code>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => setError(null)}>Close</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
|
@ -17,3 +17,5 @@ anyhow = "1.0.86"
|
||||||
zip = { version = "2.1.3", default-features = false, features = ["deflate"] }
|
zip = { version = "2.1.3", default-features = false, features = ["deflate"] }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
|
ansi-to-html = "0.2.1"
|
||||||
|
colored = "2.1.0"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
io::{Cursor, Write},
|
io::{Cursor, Write},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -24,6 +24,9 @@ extern "C" {
|
||||||
fn log(s: &str);
|
fn log(s: &str);
|
||||||
#[wasm_bindgen(js_namespace = console, js_name = error)]
|
#[wasm_bindgen(js_namespace = console, js_name = error)]
|
||||||
fn log_err(s: &str);
|
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.
|
/// Compiles the given directory into datapack files.
|
||||||
|
@ -57,38 +60,38 @@ pub fn compile_zip(root_dir: JsValue) -> Option<String> {
|
||||||
|
|
||||||
// write each file to the zip archive
|
// write each file to the zip archive
|
||||||
for (path, file) in virtual_files {
|
for (path, file) in virtual_files {
|
||||||
writer
|
writer.start_file(path, SimpleFileOptions::default()).ok()?;
|
||||||
.start_file(path, SimpleFileOptions::default())
|
|
||||||
.unwrap();
|
|
||||||
match file {
|
match file {
|
||||||
VFile::Text(text) => {
|
VFile::Text(text) => {
|
||||||
writer.write_all(text.as_bytes()).unwrap();
|
writer.write_all(text.as_bytes()).ok()?;
|
||||||
}
|
}
|
||||||
VFile::Binary(data) => {
|
VFile::Binary(data) => {
|
||||||
writer.write_all(data).unwrap();
|
writer.write_all(data).ok()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.set_comment("Data pack created with Shulkerscript web compiler");
|
writer.set_comment("Data pack created with Shulkerscript web compiler");
|
||||||
|
|
||||||
writer.finish().unwrap();
|
writer.finish().ok()?;
|
||||||
|
|
||||||
Some(BASE64_STANDARD.encode(buffer.into_inner()))
|
Some(BASE64_STANDARD.encode(buffer.into_inner()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _compile(root_dir: &VFolder) -> Result<VFolder> {
|
fn _compile(root_dir: &VFolder) -> Result<VFolder> {
|
||||||
|
colored::control::set_override(true);
|
||||||
let printer = Printer::new();
|
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 {
|
struct Printer {
|
||||||
printed: Cell<bool>,
|
queue: Mutex<Vec<String>>,
|
||||||
}
|
}
|
||||||
impl<T: Display> Handler<T> for Printer {
|
impl<T: Display> Handler<T> for Printer {
|
||||||
fn receive<E: Into<T>>(&self, error: E) {
|
fn receive<E: Into<T>>(&self, error: E) {
|
||||||
log_err(&error.into().to_string());
|
self.queue.lock().unwrap().push(format!("{}", error.into()));
|
||||||
self.printed.set(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_received(&self) -> bool {
|
fn has_received(&self) -> bool {
|
||||||
|
@ -99,12 +102,23 @@ impl Printer {
|
||||||
/// Creates a new [`Printer`].
|
/// Creates a new [`Printer`].
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
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::<Vec<_>>();
|
||||||
|
show_err(&queue.join("\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
fn has_printed(&self) -> bool {
|
fn has_printed(&self) -> bool {
|
||||||
self.printed.get()
|
!self.queue.lock().unwrap().is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue