diff --git a/backend/src/api.ts b/backend/src/api.ts index c0fcf50..9131634 100644 --- a/backend/src/api.ts +++ b/backend/src/api.ts @@ -35,6 +35,12 @@ export class Session { writer: rpc.StreamMessageWriter; } | null = null; daemon: { proc: ChildProcess } | null = null; + formatter: { + proc: ChildProcess; + live: boolean; + input: string; + output: string; + } | null = null; get homedir() { return `/tmp/riju/${this.uuid}`; @@ -224,6 +230,13 @@ export class Session { } await this.runCode(msg.code); break; + case "formatCode": + if (typeof msg.code !== "string") { + this.logBadMessage(msg); + break; + } + await this.formatCode(msg.code); + break; case "lspInput": if (typeof msg.input !== "object" || !msg) { this.logBadMessage(msg); @@ -257,12 +270,11 @@ export class Session { compile, run, template, - hacks, } = this.config; if (this.term) { const pid = this.term.pty.pid; const args = this.privilegedSpawn( - bash(`kill -SIGTERM ${pid}; sleep 3; kill -SIGKILL ${pid}`) + bash(`kill -SIGTERM ${pid}; sleep 1; kill -SIGKILL ${pid}`) ); spawn(args[0], args.slice(1)); // Signal to terminalOutput message generator using closure. @@ -304,18 +316,6 @@ export class Session { ]), { input: code } ); - if (hacks && hacks.includes("ghci-config") && run) { - if (code) { - await this.run( - this.privilegedSpawn(["sh", "-c", `cat > ${this.homedir}/.ghci`]), - { input: ":load Main\nmain\n" } - ); - } else { - await this.run( - this.privilegedSpawn(["rm", "-f", `${this.homedir}/.ghci`]) - ); - } - } const termArgs = this.privilegedSpawn(bash(cmdline)); const term = { pty: pty.spawn(termArgs[0], termArgs.slice(1), { @@ -338,6 +338,66 @@ export class Session { } }; + formatCode = async (code: string) => { + if (!this.config.format) { + this.log("formatCode ignored because format is null"); + return; + } + if (this.formatter) { + const pid = this.formatter.proc.pid; + const args = this.privilegedSpawn( + bash(`kill -SIGTERM ${pid}; sleep 1; kill -SIGKILL ${pid}`) + ); + spawn(args[0], args.slice(1)); + this.formatter.live = false; + this.formatter = null; + } + const args = this.privilegedSpawn(bash(this.config.format)); + const formatter = { + proc: spawn(args[0], args.slice(1)), + live: true, + input: code, + output: "", + }; + formatter.proc.stdout!.on("data", (data) => { + if (formatter.live) { + formatter.output += data.toString("utf8"); + } + }); + formatter.proc.stderr!.on("data", (data) => { + if (formatter.live) { + this.send({ + event: "serviceLog", + service: "formatter", + output: data.toString("utf8"), + }); + } + }); + formatter.proc.on("exit", (code, signal) => { + if (code === 0) { + this.send({ + event: "formattedCode", + code: formatter.output, + originalCode: formatter.input, + }); + } else { + this.send({ + event: "serviceFailed", + service: "formatter", + error: `Exited with status ${signal || code}`, + }); + } + }); + formatter.proc.on("error", (err) => + this.send({ + event: "serviceFailed", + service: "formatter", + error: `${err}`, + }) + ); + this.formatter = formatter; + }; + teardown = async () => { try { if (this.tearingDown) { diff --git a/backend/src/langs.ts b/backend/src/langs.ts index 8d92728..e2a41c6 100644 --- a/backend/src/langs.ts +++ b/backend/src/langs.ts @@ -11,6 +11,7 @@ export interface LangConfig { createEmpty?: string; compile?: string; run: string; + format?: string; pkg?: { install: string; uninstall?: string; @@ -24,7 +25,6 @@ export interface LangConfig { lspConfig?: any; lspLang?: string; template: string; - hacks?: "ghci-config"[]; test?: { ensure?: string; }; @@ -764,9 +764,10 @@ function main(): void { haskell: { aliases: ["ghc", "ghci", "hs"], name: "Haskell", - repl: "ghci", + repl: "rm -f .ghci && ghci", main: "Main.hs", - run: "ghci", + run: "(echo ':load Main' && echo 'main') > .ghci && ghci", + format: "brittany Main.hs", lspSetup: "cp /opt/haskell/hie.yaml hie.yaml", lsp: "HIE_HOOGLE_DATABASE=/opt/haskell/hoogle.hoo hie --lsp", lspInit: { @@ -1337,6 +1338,7 @@ main = do repl: "python3 -u", main: "main.py", run: "python3 -u -i main.py", + format: "cat main.py | black -", pkg: { install: "pip3 install --user NAME", uninstall: "pip3 uninstall NAME", @@ -1350,7 +1352,7 @@ main = do }, }, }, - template: `print("Hello, world!") + template: `print('Hello, world!') `, }, قلب: { diff --git a/frontend/pages/app.ejs b/frontend/pages/app.ejs index bc2e09a..c6b046e 100644 --- a/frontend/pages/app.ejs +++ b/frontend/pages/app.ejs @@ -16,6 +16,7 @@
+ Switch to a different language