diff --git a/backend/src/api.ts b/backend/src/api.ts index b35f03c..9142ce2 100644 --- a/backend/src/api.ts +++ b/backend/src/api.ts @@ -24,6 +24,14 @@ export class Session { monacoLanguage: this.config.monacoLang, }) ); + if (this.config.template) { + this.ws.send( + JSON.stringify({ + event: "insertTemplate", + template: this.config.template, + }) + ); + } this.run().catch(console.error); ws.on("message", this.handleClientMessage); } @@ -58,15 +66,8 @@ export class Session { break; } }; - parseCmdline = (cmdline: string[] | string) => { - if (typeof cmdline === "string") { - return ["bash", "-c", cmdline]; - } else { - return cmdline; - } - }; run = async () => { - const { repl, file, suffix, run } = this.config; + const { repl, file, suffix, compile, run } = this.config; if (this.term.pty) { this.term.pty.kill(); this.term.live = false; @@ -81,8 +82,10 @@ export class Session { } }) ); - let cmdline: string[]; - if (this.code || !repl) { + let cmdline: string; + if (!run) { + cmdline = `echo 'Support for ${this.config.name} is not yet implemented.`; + } else if (this.code) { let code = this.code; if (suffix) { code += suffix; @@ -96,12 +99,17 @@ export class Session { } }) ); - cmdline = this.parseCmdline(run); + cmdline = run; + if (compile) { + cmdline = compile + " && " + run; + } + } else if (repl) { + cmdline = repl; } else { - cmdline = this.parseCmdline(repl); + return; } const term = { - pty: pty.spawn(cmdline[0], cmdline.slice(1), { + pty: pty.spawn("bash", ["-c", cmdline], { name: "xterm-color", cwd: tmpdir, env: process.env, diff --git a/backend/src/langs.ts b/backend/src/langs.ts index 3978b15..1a34cfb 100644 --- a/backend/src/langs.ts +++ b/backend/src/langs.ts @@ -1,103 +1,116 @@ export interface LangConfig { - repl?: string[]; + name: string; + monacoLang: string; + repl?: string; file?: string; prefix?: string; suffix?: string; - run?: string[] | string; - monacoLang: string; - name: string; + compile?: string; + run?: string; + template?: string; } -export const langs = { +export const langs: { [key: string]: LangConfig } = { bash: { - repl: ["bash"], - file: "main.bash", - run: ["bash", "--rcfile", "main.bash"], name: "Bash", monacoLang: "shell", + repl: "bash", + file: "main.bash", + run: "bash --rcfile main.bash", + template: 'echo "Hello, world!"', }, c: { name: "C", monacoLang: "c", + file: "main.c", + compile: "clang -Wall -Wextra main.c -o main", + run: "./main", + template: `#include + +int main() { + printf("Hello, world!\\n"); + return 0; +} +`, }, "c++": { name: "C++", monacoLang: "cpp", }, clojure: { - repl: ["clojure"], name: "Clojure", monacoLang: "clojure", + repl: "clojure", }, emacs: { - repl: ["emacs"], name: "Emacs Lisp", monacoLang: "plaintext", + repl: "emacs", }, fish: { - repl: ["env", "SHELL=/usr/bin/fish", "fish"], name: "Fish", monacoLang: "plaintext", + repl: "SHELL=/usr/bin/fish fish", }, go: { name: "Go", monacoLang: "go", }, haskell: { - repl: ["ghci"], - file: "Main.hs", - run: ["ghci", "Main.hs"], name: "Haskell", monacoLang: "plaintext", + repl: "ghci", + file: "Main.hs", + run: "ghci Main.hs", }, java: { name: "Java", monacoLang: "java", }, julia: { - repl: ["julia"], name: "Julia", monacoLang: "plaintext", + repl: "julia", }, lua: { - repl: ["lua"], name: "Lua", monacoLang: "lua", + repl: "lua", }, nodejs: { - repl: ["node"], + name: "Node.js", + monacoLang: "javascript", + repl: "node", file: "main.js", suffix: '\n;require("repl").start();', run: "node main.js", - name: "Node.js", - monacoLang: "javascript", }, python: { - repl: ["python3", "-u"], - file: "main.py", - run: ["python3", "-u", "-i", "main.py"], name: "Python", monacoLang: "python", + repl: "python3 -u", + file: "main.py", + run: "python3 -u -i main.py", }, ruby: { - repl: ["irb"], name: "Ruby", monacoLang: "ruby", + repl: "irb", }, rust: { name: "Rust", monacoLang: "rust", }, vim: { - repl: ["vim"], name: "Vimscript", monacoLang: "plaintext", + repl: "vim", }, zsh: { - repl: ["env", "SHELL=/usr/bin/zsh", "zsh"], - file: ".zshrc", - run: ["env", "ZDOTDIR=.", "zsh"], name: "Zsh", monacoLang: "shell", + repl: "SHELL=/usr/bin/zsh zsh", + file: ".zshrc", + run: "ZDOTDIR=. zsh", }, }; diff --git a/frontend/src/app.ts b/frontend/src/app.ts index 206180b..930755c 100644 --- a/frontend/src/app.ts +++ b/frontend/src/app.ts @@ -17,6 +17,8 @@ window.addEventListener("resize", () => fitAddon.fit()); const initialRetryDelayMs = 200; let retryDelayMs = initialRetryDelayMs; +let allowInsertingTemplate = true; + function tryConnect() { console.log("Connecting to server..."); socket = new WebSocket( @@ -57,6 +59,15 @@ function tryConnect() { message.monacoLanguage ); return; + case "insertTemplate": + if (typeof message.template !== "string") { + console.error("Unexpected message from server:", message); + return; + } + if (allowInsertingTemplate) { + editor.getModel().setValue(message.template); + } + return; default: console.error("Unexpected message from server:", message); return; @@ -91,6 +102,9 @@ const editor = monaco.editor.create(document.getElementById("editor"), { scrollbar: { verticalScrollbarSize: 0 }, }); window.addEventListener("resize", () => editor.layout()); +editor.onDidChangeModelContent(() => { + allowInsertingTemplate = false; +}); document.getElementById("runButton").addEventListener("click", () => { socket.send(JSON.stringify({ event: "runCode", code: editor.getValue() })); diff --git a/scripts/docker-install.bash b/scripts/docker-install.bash index 91b60ba..82f3f6a 100755 --- a/scripts/docker-install.bash +++ b/scripts/docker-install.bash @@ -38,6 +38,7 @@ bsdmainutils curl emacs-nox git +lsof make man-db nano