From 60c9e761415dbf6e7d338f025197c2b535f11128 Mon Sep 17 00:00:00 2001 From: Alexandre Tolstenko Date: Tue, 5 Mar 2024 09:02:14 -0500 Subject: [PATCH] feat: syntax training --- demo-syntax-training/package.json | 2 +- .../src/components/SyntaxTraining.tsx | 60 ++++++++++---- demo/package.json | 3 +- demo/webpack.config.js | 20 ++--- webapp/src/app/page.tsx | 83 ++++++++++++------- 5 files changed, 111 insertions(+), 57 deletions(-) diff --git a/demo-syntax-training/package.json b/demo-syntax-training/package.json index d6781365..20365e5d 100644 --- a/demo-syntax-training/package.json +++ b/demo-syntax-training/package.json @@ -14,7 +14,7 @@ "antd": "^5.12.2", "comlink": "^4.4.1", "compression-webpack-plugin": "^10.0.0", - "emception": "^1.0.11-beta.1", + "emception": "1.0.15", "markdown-to-jsx": "^7.3.2", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/demo-syntax-training/src/components/SyntaxTraining.tsx b/demo-syntax-training/src/components/SyntaxTraining.tsx index aa85cdc0..6fa9d045 100644 --- a/demo-syntax-training/src/components/SyntaxTraining.tsx +++ b/demo-syntax-training/src/components/SyntaxTraining.tsx @@ -3,19 +3,19 @@ import {AssignmentBasev1_0_0} from "../assignments/assignment.base.v1.0.0"; const path = require('path'); import { CopyOutlined, PlayCircleFilled, UndoOutlined } from "@ant-design/icons"; import { Editor } from "@monaco-editor/react"; -import { Breadcrumb, Button, Col, Layout, Menu, notification, Row, Space, Input } from "antd"; +import {Breadcrumb, Button, Col, Layout, Menu, notification, Row, Space, Input, message} from "antd"; const { TextArea } = Input; import * as Comlink from "comlink"; import { editor } from "monaco-editor"; import React, {useEffect, useRef, useState} from "react"; -import Emception from "./emception"; import { HelloWorldCPP } from "../assignments/intro-cpp/hello-world-cpp"; import Markdown from 'markdown-to-jsx' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { dark } from 'react-syntax-highlighter/dist/esm/styles/prism'; import {write} from "node:fs"; +import Emception from "./emception"; const CodeBlock = ({ children }: { children: React.ReactElement }) => { const { className, children: code } = children.props; @@ -55,14 +55,17 @@ const SyntaxTrainingPage: React.FC = ({ language = "cpp", height = "20vh" }) => { - const [cppFlags, setCppFlags] = useState("-O2 -fexceptions --proxy-to-worker -sEXIT_RUNTIME=1 -std=c++20"); + const [cppFlags, setCppFlags] = useState("-O2 -fexceptions --proxy-to-worker -sEXIT_RUNTIME=1 -std=c++20"); + + const [emceptionLoaded, setEmceptionLoaded] = useState(false); const [api, contextHolder] = notification.useNotification(); let [consoleOutput, setConsoleOutput] = useState(""); - let emception: Emception; + const [emception, setEmception] = useState | null>(null); - const writeLineToConsole = (str: string) => { + const writeLineToConsole = (str: any) => { + console.log(str); consoleOutput+= str + "\n"; console.log(consoleOutput); setConsoleOutput(consoleOutput); @@ -86,18 +89,40 @@ const SyntaxTrainingPage: React.FC = ({ async function loadEmception(): Promise { showNotification("Loading emception..."); + if(emceptionLoaded) + return; + setEmceptionLoaded(true); + console.log("load worker"); // todo: is it possible to not refer as url? const emceptionWorker = new Worker(new URL('./emception.worker.ts', import.meta.url), { type: 'module' }); - emception = Comlink.wrap(emceptionWorker); + emceptionWorker.onerror = (e) => { + console.error(e); + showNotification("Emception worker error"); + } + + console.log("Post message to worker"); + + //let emception: Comlink.Remote = Comlink.wrap(emceptionWorker); + let emception: Comlink.Remote = Comlink.wrap(emceptionWorker); + + console.log("Post wrap"); - emception.onstdout = Comlink.proxy(console.log); - emception.onstderr = Comlink.proxy(console.log); - emception.onprocessstart = Comlink.proxy(console.log); - emception.onprocessend = Comlink.proxy(console.log); + setEmception(emception); + + console.log("Post set"); + + emception.onstdout.bind(console.log); + emception.onstderr.bind(console.log); + emception.onprocessstart.bind(console.log); + emception.onprocessend.bind(console.log); + + console.log("Post bind"); await emception.init(); + + console.log("Post init"); showNotification("Emception intialized"); } @@ -139,8 +164,14 @@ const SyntaxTrainingPage: React.FC = ({ }; const onRunClick = async () => { - try { + // try { clearConsole(); + if (!emception) { + showNotification("Emception not loaded"); + console.log("Emception not loaded"); + return; + } + const code = editorRef.current?.getValue() || ''; await emception.fileSystem.writeFile("/working/main.cpp", code); const cmd = `em++ ${cppFlags} -sSINGLE_FILE=1 -sUSE_CLOSURE_COMPILER=0 /working/main.cpp -o /working/main.js`; @@ -155,10 +186,11 @@ const SyntaxTrainingPage: React.FC = ({ eval(content); } else { writeLineToConsole(`Emception compilation failed`); + writeLineToConsole(JSON.stringify(result)); } - } catch (e) { - writeLineToConsole(JSON.stringify(e)); - } + // } catch (e) { + // writeLineToConsole(JSON.stringify(e)); + // } } const showNotification = (message: string) => { diff --git a/demo/package.json b/demo/package.json index b5b2278e..6ab128cf 100755 --- a/demo/package.json +++ b/demo/package.json @@ -21,7 +21,8 @@ "webpack-mode": "^1.1.0", "worker-loader": "^3.0.8", "xterm": "^4.14.1", - "xterm-addon-fit": "^0.5.0" + "xterm-addon-fit": "^0.5.0", + "emception": "^1.0.15" }, "dependencies": { "antd": "^5.12.2", diff --git a/demo/webpack.config.js b/demo/webpack.config.js index d6a03021..6949298c 100755 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -14,7 +14,7 @@ module.exports = { }, resolve: { alias: { - emception: "../build/emception", + // emception: "../build/emception", }, fallback: { "llvm-box.wasm": false, @@ -31,15 +31,15 @@ module.exports = { title: "Emception", }), new MonacoWebpackPlugin({ languages: ["cpp"] }), - new CopyWebpackPlugin({ - patterns: [{ - from: "../build/emception/brotli/brotli.wasm", - to: "brotli/brotli.wasm" - }, { - from: "../build/emception/wasm-package/wasm-package.wasm", - to: "wasm-package/wasm-package.wasm" - }], - }), + // new CopyWebpackPlugin({ + // patterns: [{ + // from: "../build/emception/brotli/brotli.wasm", + // to: "brotli/brotli.wasm" + // }, { + // from: "../build/emception/wasm-package/wasm-package.wasm", + // to: "wasm-package/wasm-package.wasm" + // }], + // }), new CompressionPlugin({ exclude: /\.br$/, }), diff --git a/webapp/src/app/page.tsx b/webapp/src/app/page.tsx index b02cacf9..ead37eb2 100644 --- a/webapp/src/app/page.tsx +++ b/webapp/src/app/page.tsx @@ -1,8 +1,8 @@ 'use client'; -import { DatePicker } from 'antd'; +import {DatePicker, Space} from 'antd'; import { Button } from 'antd'; -import * as monaco from "monaco-editor/esm/vs/editor/editor.api"; +import Editor, {Monaco} from "@monaco-editor/react"; import { Terminal } from "xterm"; import { FitAddon } from 'xterm-addon-fit'; import Split from "split-grid"; @@ -14,40 +14,39 @@ import EmceptionWorker from "./emception.worker.js"; import "./style.css"; import "xterm/css/xterm.css"; +import React from "react"; +import {editor} from "monaco-editor"; +import IModelContentChangedEvent = editor.IModelContentChangedEvent; +import Emception from "@/app/emception"; -const emception = EmceptionWorker; +const emception = Emception; async function run() { console.log("run"); } export default function Home() { // const emception = EmceptionWorker; - const editorContainer = document.createElement("div"); - const editor = monaco.editor.create(editorContainer, { - value: "", - language: "cpp", - theme: "vs-dark", - }); - - const terminalContainer = document.createElement("div"); - const terminal = new Terminal({ - convertEol: true, - theme: { - background: "#1e1e1e", - foreground: "#d4d4d4", - }, - }); - terminal.open(terminalContainer); - - const terminalFitAddon = new FitAddon(); - terminal.loadAddon(terminalFitAddon); - - editor.setValue(`#include -int main(void) { - std::cout << "hello world!\\n"; - return 0; -} -`); + // const editorContainer = document.createElement("div"); + // const editor = monaco.editor.create(editorContainer, { + // value: "", + // language: "cpp", + // theme: "vs-dark", + // }); + + // const terminalContainer = document.createElement("div"); + // const terminal = new Terminal({ + // convertEol: true, + // theme: { + // background: "#1e1e1e", + // foreground: "#d4d4d4", + // }, + // }); + // terminal.open(terminalContainer); + + // const terminalFitAddon = new FitAddon(); + // terminal.loadAddon(terminalFitAddon); + + // emception.onstdout = Comlink.proxy((str: string) => terminal.write(str + "\n")); // emception.onstderr = Comlink.proxy((str: string) => terminal.write(str + "\n")); @@ -57,6 +56,28 @@ int main(void) { // terminalFitAddon.fit(); // }); - // call run on click - return ; + const initialCode = `#include +int main(void) { + std::cout << "hello world!\\n"; + return 0; +}`; + + const [code, setCode] = React.useState(initialCode); + + const run = async () => { + console.log("run"); + const emception = new Emception(); + console.log('init'); + await emception.init(); + console.log('run'); + }; + + return + + { + if (value) { + setCode(value); + } + } } /> + }