diff options
author | Hood Chatham <roberthoodchatham@gmail.com> | 2024-12-05 00:25:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-05 00:25:06 (GMT) |
commit | 2f1cee8477e22bfc36a704310e4c0f409357e7e9 (patch) | |
tree | fe241cc2f29bd4c61fbc31cfcddd2e4642fdc101 | |
parent | 94b8f8b40943bf38cf5c454773a3fb8f4ff71e01 (diff) | |
download | cpython-2f1cee8477e22bfc36a704310e4c0f409357e7e9.zip cpython-2f1cee8477e22bfc36a704310e4c0f409357e7e9.tar.gz cpython-2f1cee8477e22bfc36a704310e4c0f409357e7e9.tar.bz2 |
gh-127111: Apply prettier formatter to Emscripten web example (#127551)
Cleaned up formatting (and a stray closing tag) of the web example HTML and JS.
-rw-r--r-- | Tools/wasm/emscripten/web_example/python.html | 782 | ||||
-rw-r--r-- | Tools/wasm/emscripten/web_example/python.worker.mjs | 175 |
2 files changed, 511 insertions, 446 deletions
diff --git a/Tools/wasm/emscripten/web_example/python.html b/Tools/wasm/emscripten/web_example/python.html index fae1e9a..078f86e 100644 --- a/Tools/wasm/emscripten/web_example/python.html +++ b/Tools/wasm/emscripten/web_example/python.html @@ -1,373 +1,433 @@ -<!DOCTYPE html> +<!doctype html> <html lang="en"> -<head> - <meta charset="UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="author" content="Katie Bell"> - <meta name="description" content="Simple REPL for Python WASM"> - <title>wasm-python terminal</title> - <link rel="stylesheet" href="https://unpkg.com/xterm@4.18.0/css/xterm.css" crossorigin integrity="sha384-4eEEn/eZgVHkElpKAzzPx/Kow/dTSgFk1BNe+uHdjHa+NkZJDh5Vqkq31+y7Eycd"/> - <style> - body { - font-family: arial; - max-width: 800px; - margin: 0 auto - } - #code { - width: 100%; - height: 180px; - } - #info { - padding-top: 20px; - } - .button-container { - display: flex; - justify-content: end; - height: 50px; - align-items: center; - gap: 10px; - } - button { - padding: 6px 18px; - } - </style> - <script src="https://unpkg.com/xterm@4.18.0/lib/xterm.js" crossorigin integrity="sha384-yYdNmem1ioP5Onm7RpXutin5A8TimLheLNQ6tnMi01/ZpxXdAwIm2t4fJMx1Djs+"/></script> - <script type="module"> -class WorkerManager { - constructor(workerURL, standardIO, readyCallBack, finishedCallback) { - this.workerURL = workerURL - this.worker = null - this.standardIO = standardIO - this.readyCallBack = readyCallBack - this.finishedCallback = finishedCallback - - this.initialiseWorker() - } - - async initialiseWorker() { - if (!this.worker) { - this.worker = new Worker(this.workerURL, {type: "module"}) - this.worker.addEventListener('message', this.handleMessageFromWorker) - } - } - - async run(options) { - this.worker.postMessage({ - type: 'run', - args: options.args || [], - files: options.files || {} - }) - } - - reset() { - if (this.worker) { - this.worker.terminate() - this.worker = null - } - this.standardIO.message('Worker process terminated.') - this.initialiseWorker() - } - - handleStdinData(inputValue) { - if (this.stdinbuffer && this.stdinbufferInt) { - let startingIndex = 1 - if (this.stdinbufferInt[0] > 0) { - startingIndex = this.stdinbufferInt[0] + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="author" content="Katie Bell" /> + <meta name="description" content="Simple REPL for Python WASM" /> + <title>wasm-python terminal</title> + <link + rel="stylesheet" + href="https://unpkg.com/xterm@4.18.0/css/xterm.css" + crossorigin + integrity="sha384-4eEEn/eZgVHkElpKAzzPx/Kow/dTSgFk1BNe+uHdjHa+NkZJDh5Vqkq31+y7Eycd" + /> + <style> + body { + font-family: arial; + max-width: 800px; + margin: 0 auto; } - const data = new TextEncoder().encode(inputValue) - data.forEach((value, index) => { - this.stdinbufferInt[startingIndex + index] = value - }) - - this.stdinbufferInt[0] = startingIndex + data.length - 1 - Atomics.notify(this.stdinbufferInt, 0, 1) - } - } - - handleMessageFromWorker = (event) => { - const type = event.data.type - if (type === 'ready') { - this.readyCallBack() - } else if (type === 'stdout') { - this.standardIO.stdout(event.data.stdout) - } else if (type === 'stderr') { - this.standardIO.stderr(event.data.stderr) - } else if (type === 'stdin') { - // Leave it to the terminal to decide whether to chunk it into lines - // or send characters depending on the use case. - this.stdinbuffer = event.data.buffer - this.stdinbufferInt = new Int32Array(this.stdinbuffer) - this.standardIO.stdin().then((inputValue) => { - this.handleStdinData(inputValue) - }) - } else if (type === 'finished') { - this.standardIO.message(`Exited with status: ${event.data.returnCode}`) - this.finishedCallback() - } - } -} - -class WasmTerminal { - - constructor() { - this.inputBuffer = new BufferQueue(); - this.input = '' - this.resolveInput = null - this.activeInput = false - this.inputStartCursor = null - - this.xterm = new Terminal( - { scrollback: 10000, fontSize: 14, theme: { background: '#1a1c1f' }, cols: 100} - ); - - this.xterm.onKey((keyEvent) => { - // Fix for iOS Keyboard Jumping on space - if (keyEvent.key === " ") { - keyEvent.domEvent.preventDefault(); + #code { + width: 100%; + height: 180px; } - }); - - this.xterm.onData(this.handleTermData) - } - - open(container) { - this.xterm.open(container); - } - - handleTermData = (data) => { - const ord = data.charCodeAt(0); - data = data.replace(/\r(?!\n)/g, "\n") // Convert lone CRs to LF - - // Handle pasted data - if (data.length > 1 && data.includes("\n")) { - let alreadyWrittenChars = 0; - // If line already had data on it, merge pasted data with it - if (this.input != '') { - this.inputBuffer.addData(this.input); - alreadyWrittenChars = this.input.length; - this.input = ''; + #info { + padding-top: 20px; } - this.inputBuffer.addData(data); - // If input is active, write the first line - if (this.activeInput) { - let line = this.inputBuffer.nextLine(); - this.writeLine(line.slice(alreadyWrittenChars)); - this.resolveInput(line); - this.activeInput = false; + .button-container { + display: flex; + justify-content: end; + height: 50px; + align-items: center; + gap: 10px; } - // When input isn't active, add to line buffer - } else if (!this.activeInput) { - // Skip non-printable characters - if (!(ord === 0x1b || ord == 0x7f || ord < 32)) { - this.inputBuffer.addData(data); + button { + padding: 6px 18px; } - // TODO: Handle ANSI escape sequences - } else if (ord === 0x1b) { - // Handle special characters - } else if (ord < 32 || ord === 0x7f) { - switch (data) { - case "\x0c": // CTRL+L - this.clear(); - break; - case "\n": // ENTER - case "\x0a": // CTRL+J - case "\x0d": // CTRL+M - this.resolveInput(this.input + this.writeLine('\n')); - this.input = ''; + </style> + <script + src="https://unpkg.com/xterm@4.18.0/lib/xterm.js" + crossorigin + integrity="sha384-yYdNmem1ioP5Onm7RpXutin5A8TimLheLNQ6tnMi01/ZpxXdAwIm2t4fJMx1Djs+" + /> + <script type="module"> + class WorkerManager { + constructor( + workerURL, + standardIO, + readyCallBack, + finishedCallback, + ) { + this.workerURL = workerURL; + this.worker = null; + this.standardIO = standardIO; + this.readyCallBack = readyCallBack; + this.finishedCallback = finishedCallback; + + this.initialiseWorker(); + } + + async initialiseWorker() { + if (!this.worker) { + this.worker = new Worker(this.workerURL, { + type: "module", + }); + this.worker.addEventListener( + "message", + this.handleMessageFromWorker, + ); + } + } + + async run(options) { + this.worker.postMessage({ + type: "run", + args: options.args || [], + files: options.files || {}, + }); + } + + reset() { + if (this.worker) { + this.worker.terminate(); + this.worker = null; + } + this.standardIO.message("Worker process terminated."); + this.initialiseWorker(); + } + + handleStdinData(inputValue) { + if (this.stdinbuffer && this.stdinbufferInt) { + let startingIndex = 1; + if (this.stdinbufferInt[0] > 0) { + startingIndex = this.stdinbufferInt[0]; + } + const data = new TextEncoder().encode(inputValue); + data.forEach((value, index) => { + this.stdinbufferInt[startingIndex + index] = value; + }); + + this.stdinbufferInt[0] = + startingIndex + data.length - 1; + Atomics.notify(this.stdinbufferInt, 0, 1); + } + } + + handleMessageFromWorker = (event) => { + const type = event.data.type; + if (type === "ready") { + this.readyCallBack(); + } else if (type === "stdout") { + this.standardIO.stdout(event.data.stdout); + } else if (type === "stderr") { + this.standardIO.stderr(event.data.stderr); + } else if (type === "stdin") { + // Leave it to the terminal to decide whether to chunk it into lines + // or send characters depending on the use case. + this.stdinbuffer = event.data.buffer; + this.stdinbufferInt = new Int32Array(this.stdinbuffer); + this.standardIO.stdin().then((inputValue) => { + this.handleStdinData(inputValue); + }); + } else if (type === "finished") { + this.standardIO.message( + `Exited with status: ${event.data.returnCode}`, + ); + this.finishedCallback(); + } + }; + } + + class WasmTerminal { + constructor() { + this.inputBuffer = new BufferQueue(); + this.input = ""; + this.resolveInput = null; this.activeInput = false; - break; - case "\x7F": // BACKSPACE - case "\x08": // CTRL+H - this.handleCursorErase(true); - break; - case "\x04": // CTRL+D - // Send empty input - if (this.input === '') { - this.resolveInput('') - this.activeInput = false; + this.inputStartCursor = null; + + this.xterm = new Terminal({ + scrollback: 10000, + fontSize: 14, + theme: { background: "#1a1c1f" }, + cols: 100, + }); + + this.xterm.onKey((keyEvent) => { + // Fix for iOS Keyboard Jumping on space + if (keyEvent.key === " ") { + keyEvent.domEvent.preventDefault(); + } + }); + + this.xterm.onData(this.handleTermData); + } + + open(container) { + this.xterm.open(container); + } + + handleTermData = (data) => { + const ord = data.charCodeAt(0); + data = data.replace(/\r(?!\n)/g, "\n"); // Convert lone CRs to LF + + // Handle pasted data + if (data.length > 1 && data.includes("\n")) { + let alreadyWrittenChars = 0; + // If line already had data on it, merge pasted data with it + if (this.input != "") { + this.inputBuffer.addData(this.input); + alreadyWrittenChars = this.input.length; + this.input = ""; + } + this.inputBuffer.addData(data); + // If input is active, write the first line + if (this.activeInput) { + let line = this.inputBuffer.nextLine(); + this.writeLine(line.slice(alreadyWrittenChars)); + this.resolveInput(line); + this.activeInput = false; + } + // When input isn't active, add to line buffer + } else if (!this.activeInput) { + // Skip non-printable characters + if (!(ord === 0x1b || ord == 0x7f || ord < 32)) { + this.inputBuffer.addData(data); + } + // TODO: Handle ANSI escape sequences + } else if (ord === 0x1b) { + // Handle special characters + } else if (ord < 32 || ord === 0x7f) { + switch (data) { + case "\x0c": // CTRL+L + this.clear(); + break; + case "\n": // ENTER + case "\x0a": // CTRL+J + case "\x0d": // CTRL+M + this.resolveInput( + this.input + this.writeLine("\n"), + ); + this.input = ""; + this.activeInput = false; + break; + case "\x7F": // BACKSPACE + case "\x08": // CTRL+H + this.handleCursorErase(true); + break; + case "\x04": // CTRL+D + // Send empty input + if (this.input === "") { + this.resolveInput(""); + this.activeInput = false; + } + } + } else { + this.handleCursorInsert(data); + } + }; + + writeLine(line) { + this.xterm.write(line.slice(0, -1)); + this.xterm.write("\r\n"); + return line; + } + + handleCursorInsert(data) { + this.input += data; + this.xterm.write(data); + } + + handleCursorErase() { + // Don't delete past the start of input + if ( + this.xterm.buffer.active.cursorX <= + this.inputStartCursor + ) { + return; + } + this.input = this.input.slice(0, -1); + this.xterm.write("\x1B[D"); + this.xterm.write("\x1B[P"); + } + + prompt = async () => { + this.activeInput = true; + // Hack to allow stdout/stderr to finish before we figure out where input starts + setTimeout(() => { + this.inputStartCursor = + this.xterm.buffer.active.cursorX; + }, 1); + // If line buffer has a line ready, send it immediately + if (this.inputBuffer.hasLineReady()) { + return new Promise((resolve, reject) => { + resolve( + this.writeLine(this.inputBuffer.nextLine()), + ); + this.activeInput = false; + }); + // If line buffer has an incomplete line, use it for the active line + } else if (this.inputBuffer.lastLineIsIncomplete()) { + // Hack to ensure cursor input start doesn't end up after user input + setTimeout(() => { + this.handleCursorInsert( + this.inputBuffer.nextLine(), + ); + }, 1); } + return new Promise((resolve, reject) => { + this.resolveInput = (value) => { + resolve(value); + }; + }); + }; + + clear() { + this.xterm.clear(); + } + + print(charCode) { + let array = [charCode]; + if (charCode == 10) { + array = [13, 10]; // Replace \n with \r\n + } + this.xterm.write(new Uint8Array(array)); + } } - } else { - this.handleCursorInsert(data); - } - } - - writeLine(line) { - this.xterm.write(line.slice(0, -1)) - this.xterm.write('\r\n'); - return line; - } - - handleCursorInsert(data) { - this.input += data; - this.xterm.write(data) - } - - handleCursorErase() { - // Don't delete past the start of input - if (this.xterm.buffer.active.cursorX <= this.inputStartCursor) { - return - } - this.input = this.input.slice(0, -1) - this.xterm.write('\x1B[D') - this.xterm.write('\x1B[P') - } - - prompt = async () => { - this.activeInput = true - // Hack to allow stdout/stderr to finish before we figure out where input starts - setTimeout(() => {this.inputStartCursor = this.xterm.buffer.active.cursorX}, 1) - // If line buffer has a line ready, send it immediately - if (this.inputBuffer.hasLineReady()) { - return new Promise((resolve, reject) => { - resolve(this.writeLine(this.inputBuffer.nextLine())); - this.activeInput = false; - }) - // If line buffer has an incomplete line, use it for the active line - } else if (this.inputBuffer.lastLineIsIncomplete()) { - // Hack to ensure cursor input start doesn't end up after user input - setTimeout(() => {this.handleCursorInsert(this.inputBuffer.nextLine())}, 1); - } - return new Promise((resolve, reject) => { - this.resolveInput = (value) => { - resolve(value) + + class BufferQueue { + constructor(xterm) { + this.buffer = []; + } + + isEmpty() { + return this.buffer.length == 0; + } + + lastLineIsIncomplete() { + return ( + !this.isEmpty() && + !this.buffer[this.buffer.length - 1].endsWith("\n") + ); + } + + hasLineReady() { + return !this.isEmpty() && this.buffer[0].endsWith("\n"); + } + + addData(data) { + let lines = data.match(/.*(\n|$)/g); + if (this.lastLineIsIncomplete()) { + this.buffer[this.buffer.length - 1] += lines.shift(); + } + for (let line of lines) { + this.buffer.push(line); + } + } + + nextLine() { + return this.buffer.shift(); + } } - }) - } - - clear() { - this.xterm.clear(); - } - - print(charCode) { - let array = [charCode]; - if (charCode == 10) { - array = [13, 10]; // Replace \n with \r\n - } - this.xterm.write(new Uint8Array(array)); - } -} - -class BufferQueue { - constructor(xterm) { - this.buffer = [] - } - - isEmpty() { - return this.buffer.length == 0 - } - - lastLineIsIncomplete() { - return !this.isEmpty() && !this.buffer[this.buffer.length-1].endsWith("\n") - } - - hasLineReady() { - return !this.isEmpty() && this.buffer[0].endsWith("\n") - } - - addData(data) { - let lines = data.match(/.*(\n|$)/g) - if (this.lastLineIsIncomplete()) { - this.buffer[this.buffer.length-1] += lines.shift() - } - for (let line of lines) { - this.buffer.push(line) - } - } - - nextLine() { - return this.buffer.shift() - } -} - -const runButton = document.getElementById('run') -const replButton = document.getElementById('repl') -const stopButton = document.getElementById('stop') -const clearButton = document.getElementById('clear') - -const codeBox = document.getElementById('codebox') - -window.onload = () => { - const terminal = new WasmTerminal() - terminal.open(document.getElementById('terminal')) - - const stdio = { - stdout: (charCode) => { terminal.print(charCode) }, - stderr: (charCode) => { terminal.print(charCode) }, - stdin: async () => { - return await terminal.prompt() - }, - message: (text) => { terminal.writeLine(`\r\n${text}\r\n`) }, - } - - const programRunning = (isRunning) => { - if (isRunning) { - replButton.setAttribute('disabled', true) - runButton.setAttribute('disabled', true) - stopButton.removeAttribute('disabled') - } else { - replButton.removeAttribute('disabled') - runButton.removeAttribute('disabled') - stopButton.setAttribute('disabled', true) - } - } - - runButton.addEventListener('click', (e) => { - terminal.clear() - programRunning(true) - const code = codeBox.value - pythonWorkerManager.run({args: ['main.py'], files: {'main.py': code}}) - }) - - replButton.addEventListener('click', (e) => { - terminal.clear() - programRunning(true) - // Need to use "-i -" to force interactive mode. - // Looks like isatty always returns false in emscripten - pythonWorkerManager.run({args: ['-i', '-'], files: {}}) - }) - - stopButton.addEventListener('click', (e) => { - programRunning(false) - pythonWorkerManager.reset() - }) - - clearButton.addEventListener('click', (e) => { - terminal.clear() - }) - - const readyCallback = () => { - replButton.removeAttribute('disabled') - runButton.removeAttribute('disabled') - clearButton.removeAttribute('disabled') - } - - const finishedCallback = () => { - programRunning(false) - } - - const pythonWorkerManager = new WorkerManager('./python.worker.mjs', stdio, readyCallback, finishedCallback) -} - </script> -</head> -<body> - <h1>Simple REPL for Python WASM</h1> -<textarea id="codebox" cols="108" rows="16"> + + const runButton = document.getElementById("run"); + const replButton = document.getElementById("repl"); + const stopButton = document.getElementById("stop"); + const clearButton = document.getElementById("clear"); + + const codeBox = document.getElementById("codebox"); + + window.onload = () => { + const terminal = new WasmTerminal(); + terminal.open(document.getElementById("terminal")); + + const stdio = { + stdout: (charCode) => { + terminal.print(charCode); + }, + stderr: (charCode) => { + terminal.print(charCode); + }, + stdin: async () => { + return await terminal.prompt(); + }, + message: (text) => { + terminal.writeLine(`\r\n${text}\r\n`); + }, + }; + + const programRunning = (isRunning) => { + if (isRunning) { + replButton.setAttribute("disabled", true); + runButton.setAttribute("disabled", true); + stopButton.removeAttribute("disabled"); + } else { + replButton.removeAttribute("disabled"); + runButton.removeAttribute("disabled"); + stopButton.setAttribute("disabled", true); + } + }; + + runButton.addEventListener("click", (e) => { + terminal.clear(); + programRunning(true); + const code = codeBox.value; + pythonWorkerManager.run({ + args: ["main.py"], + files: { "main.py": code }, + }); + }); + + replButton.addEventListener("click", (e) => { + terminal.clear(); + programRunning(true); + // Need to use "-i -" to force interactive mode. + // Looks like isatty always returns false in emscripten + pythonWorkerManager.run({ args: ["-i", "-"], files: {} }); + }); + + stopButton.addEventListener("click", (e) => { + programRunning(false); + pythonWorkerManager.reset(); + }); + + clearButton.addEventListener("click", (e) => { + terminal.clear(); + }); + + const readyCallback = () => { + replButton.removeAttribute("disabled"); + runButton.removeAttribute("disabled"); + clearButton.removeAttribute("disabled"); + }; + + const finishedCallback = () => { + programRunning(false); + }; + + const pythonWorkerManager = new WorkerManager( + "./python.worker.mjs", + stdio, + readyCallback, + finishedCallback, + ); + }; + </script> + </head> + <body> + <h1>Simple REPL for Python WASM</h1> + <textarea id="codebox" cols="108" rows="16"> print('Welcome to WASM!') -</textarea> - <div class="button-container"> - <button id="run" disabled>Run</button> - <button id="repl" disabled>Start REPL</button> - <button id="stop" disabled>Stop</button> - <button id="clear" disabled>Clear</button> - </div> - <div id="terminal"></div> - <div id="info"> - The simple REPL provides a limited Python experience in the browser. - <a href="https://github.com/python/cpython/blob/main/Tools/wasm/README.md"> - Tools/wasm/README.md</a> contains a list of known limitations and - issues. Networking, subprocesses, and threading are not available. - </div> -</body> +</textarea + > + <div class="button-container"> + <button id="run" disabled>Run</button> + <button id="repl" disabled>Start REPL</button> + <button id="stop" disabled>Stop</button> + <button id="clear" disabled>Clear</button> + </div> + <div id="terminal"></div> + <div id="info"> + The simple REPL provides a limited Python experience in the browser. + <a + href="https://github.com/python/cpython/blob/main/Tools/wasm/README.md" + > + Tools/wasm/README.md + </a> + contains a list of known limitations and issues. Networking, + subprocesses, and threading are not available. + </div> + </body> </html> diff --git a/Tools/wasm/emscripten/web_example/python.worker.mjs b/Tools/wasm/emscripten/web_example/python.worker.mjs index 42c2e1e..8043e41 100644 --- a/Tools/wasm/emscripten/web_example/python.worker.mjs +++ b/Tools/wasm/emscripten/web_example/python.worker.mjs @@ -1,104 +1,109 @@ import createEmscriptenModule from "./python.mjs"; class StdinBuffer { - constructor() { - this.sab = new SharedArrayBuffer(128 * Int32Array.BYTES_PER_ELEMENT) - this.buffer = new Int32Array(this.sab) - this.readIndex = 1; - this.numberOfCharacters = 0; - this.sentNull = true - } + constructor() { + this.sab = new SharedArrayBuffer(128 * Int32Array.BYTES_PER_ELEMENT); + this.buffer = new Int32Array(this.sab); + this.readIndex = 1; + this.numberOfCharacters = 0; + this.sentNull = true; + } - prompt() { - this.readIndex = 1 - Atomics.store(this.buffer, 0, -1) - postMessage({ - type: 'stdin', - buffer: this.sab - }) - Atomics.wait(this.buffer, 0, -1) - this.numberOfCharacters = this.buffer[0] - } + prompt() { + this.readIndex = 1; + Atomics.store(this.buffer, 0, -1); + postMessage({ + type: "stdin", + buffer: this.sab, + }); + Atomics.wait(this.buffer, 0, -1); + this.numberOfCharacters = this.buffer[0]; + } - stdin = () => { - while (this.numberOfCharacters + 1 === this.readIndex) { - if (!this.sentNull) { - // Must return null once to indicate we're done for now. - this.sentNull = true - return null - } - this.sentNull = false - // Prompt will reset this.readIndex to 1 - this.prompt() - } - const char = this.buffer[this.readIndex] - this.readIndex += 1 - return char + stdin = () => { + while (this.numberOfCharacters + 1 === this.readIndex) { + if (!this.sentNull) { + // Must return null once to indicate we're done for now. + this.sentNull = true; + return null; + } + this.sentNull = false; + // Prompt will reset this.readIndex to 1 + this.prompt(); } + const char = this.buffer[this.readIndex]; + this.readIndex += 1; + return char; + }; } const stdout = (charCode) => { - if (charCode) { - postMessage({ - type: 'stdout', - stdout: charCode, - }) - } else { - console.log(typeof charCode, charCode) - } -} + if (charCode) { + postMessage({ + type: "stdout", + stdout: charCode, + }); + } else { + console.log(typeof charCode, charCode); + } +}; const stderr = (charCode) => { - if (charCode) { - postMessage({ - type: 'stderr', - stderr: charCode, - }) - } else { - console.log(typeof charCode, charCode) - } -} + if (charCode) { + postMessage({ + type: "stderr", + stderr: charCode, + }); + } else { + console.log(typeof charCode, charCode); + } +}; -const stdinBuffer = new StdinBuffer() +const stdinBuffer = new StdinBuffer(); const emscriptenSettings = { - noInitialRun: true, - stdin: stdinBuffer.stdin, - stdout: stdout, - stderr: stderr, - onRuntimeInitialized: () => { - postMessage({type: 'ready', stdinBuffer: stdinBuffer.sab}) - }, - async preRun(Module) { - const versionHex = Module.HEAPU32[Module._Py_Version/4].toString(16); - const versionTuple = versionHex.padStart(8, "0").match(/.{1,2}/g).map((x) => parseInt(x, 16)); - const [major, minor, ..._] = versionTuple; - // Prevent complaints about not finding exec-prefix by making a lib-dynload directory - Module.FS.mkdirTree(`/lib/python${major}.${minor}/lib-dynload/`); - Module.addRunDependency("install-stdlib"); - const resp = await fetch(`python${major}.${minor}.zip`); - const stdlibBuffer = await resp.arrayBuffer(); - Module.FS.writeFile(`/lib/python${major}${minor}.zip`, new Uint8Array(stdlibBuffer), { canOwn: true }); - Module.removeRunDependency("install-stdlib"); - } -} + noInitialRun: true, + stdin: stdinBuffer.stdin, + stdout: stdout, + stderr: stderr, + onRuntimeInitialized: () => { + postMessage({ type: "ready", stdinBuffer: stdinBuffer.sab }); + }, + async preRun(Module) { + const versionHex = Module.HEAPU32[Module._Py_Version / 4].toString(16); + const versionTuple = versionHex + .padStart(8, "0") + .match(/.{1,2}/g) + .map((x) => parseInt(x, 16)); + const [major, minor, ..._] = versionTuple; + // Prevent complaints about not finding exec-prefix by making a lib-dynload directory + Module.FS.mkdirTree(`/lib/python${major}.${minor}/lib-dynload/`); + Module.addRunDependency("install-stdlib"); + const resp = await fetch(`python${major}.${minor}.zip`); + const stdlibBuffer = await resp.arrayBuffer(); + Module.FS.writeFile( + `/lib/python${major}${minor}.zip`, + new Uint8Array(stdlibBuffer), + { canOwn: true }, + ); + Module.removeRunDependency("install-stdlib"); + }, +}; const modulePromise = createEmscriptenModule(emscriptenSettings); - onmessage = async (event) => { - if (event.data.type === 'run') { - const Module = await modulePromise; - if (event.data.files) { - for (const [filename, contents] of Object.entries(event.data.files)) { - Module.FS.writeFile(filename, contents) - } - } - const ret = Module.callMain(event.data.args); - postMessage({ - type: 'finished', - returnCode: ret - }) + if (event.data.type === "run") { + const Module = await modulePromise; + if (event.data.files) { + for (const [filename, contents] of Object.entries(event.data.files)) { + Module.FS.writeFile(filename, contents); + } } -} - + const ret = Module.callMain(event.data.args); + postMessage({ + type: "finished", + returnCode: ret, + }); + } +}; |