diff --git a/tools/playground.html b/tools/playground.html new file mode 100644 index 0000000..da39e79 --- /dev/null +++ b/tools/playground.html @@ -0,0 +1,100 @@ + + + + + + Bux Playground + + + +
+ + Try Bux in your browser — no install needed +
+
+
+ + +
+
+ +
+
+
Ctrl+Enter to run
+
+ + + + diff --git a/tools/playground.nim b/tools/playground.nim new file mode 100644 index 0000000..94f5593 --- /dev/null +++ b/tools/playground.nim @@ -0,0 +1,105 @@ +# playground.nim — Bux language web playground +# Uses hunos HTTP server to accept Bux code, compile with buxc, run, and return output +# +# Usage: nim c -r tools/playground.nim +# Then open http://localhost:8407 in browser + +import std/[os, osproc, strutils, json] +import hunos, hunos/router + +const + Buxc = "./buxc" # path to buxc binary + Port = 8407 # playground port + TimeoutMs = 5000 # max execution time (5 seconds) + +# --------------- HTML frontend --------------- +const PlaygroundHTML = staticRead("playground.html") + +# --------------- helpers --------------- + +proc compileAndRun(code: string): tuple[output: string, exitCode: int, isError: bool] = + ## Compile code with buxc, run the resulting binary, capture output. + var tmpDir = "/tmp/bux-playground-" & $getCurrentProcessId() + createDir(tmpDir) + createDir(tmpDir / "src") + + # Write Main.bux + writeFile(tmpDir / "src" / "Main.bux", code) + + # Write bux.toml + writeFile(tmpDir / "bux.toml", "[package]\nname = \"playground\"\nversion = \"0.1.0\"\ntype = \"bin\"\n\n[build]\noutput = \"Bin\"\n") + + # Build with buxc + let buildResult = execCmdEx(Buxc & " build " & tmpDir) + let buildOutput = buildResult.output + + if buildResult.exitCode != 0: + removeDir(tmpDir) + return (buildOutput, buildResult.exitCode, true) + + # Run the binary (named "playground" from bux.toml) + let binary = tmpDir / "build" / "playground" + if not fileExists(binary): + removeDir(tmpDir) + return ("Binary not found after build:\n" & buildOutput, 1, true) + + let runResult = execCmdEx("timeout " & $TimeoutMs div 1000 & " " & binary) + let runOutput = runResult.output + + # Cleanup + removeDir(tmpDir) + + return (buildOutput & "\n" & runOutput, runResult.exitCode, runResult.exitCode != 0) + +# --------------- route handlers --------------- + +proc handlePlayground(request: Request) = + var headers: HttpHeaders + headers["Content-Type"] = "text/html; charset=utf-8" + request.respond(200, headers, PlaygroundHTML) + +proc handleCompile(request: Request) = + if request.httpMethod != HttpPost: + var headers: HttpHeaders + headers["Content-Type"] = "text/plain" + request.respond(405, headers, "Method not allowed") + return + + let code = request.body + + if code.len == 0: + var headers: HttpHeaders + headers["Content-Type"] = "application/json" + request.respond(400, headers, $(%*{"error": "no code provided"})) + return + + let (output, exitCode, isError) = compileAndRun(code) + + var headers: HttpHeaders + headers["Content-Type"] = "application/json" + headers["Access-Control-Allow-Origin"] = "*" + + let response = $(%*{ + "output": output, + "exitCode": exitCode, + "isError": isError + }) + + request.respond(200, headers, response) + +# --------------- main --------------- + +proc main() = + echo "Bux Playground" + echo "Serving on http://localhost:" & $Port + echo "Open your browser and start coding!" + + var router: Router + router.get("/", handlePlayground) + router.post("/compile", handleCompile) + + let server = newServer(router) + server.serve(Port(Port)) + +when isMainModule: + main()