|
35 | 35 | <scriptsrc="https://unpkg.com/xterm@4.18.0/lib/xterm.js"crossoriginintegrity="sha384-yYdNmem1ioP5Onm7RpXutin5A8TimLheLNQ6tnMi01/ZpxXdAwIm2t4fJMx1Djs+"/></script> |
36 | 36 | <scripttype="module"> |
37 | 37 | class WorkerManager{ |
38 | | -constructor(workerURL,standardIO,readyCallBack){ |
| 38 | +constructor(workerURL,standardIO,readyCallBack,finishedCallback){ |
39 | 39 | this.workerURL=workerURL |
40 | 40 | this.worker=null |
41 | 41 | this.standardIO=standardIO |
42 | 42 | this.readyCallBack=readyCallBack |
| 43 | +this.finishedCallback=finishedCallback |
43 | 44 |
|
44 | 45 | this.initialiseWorker() |
45 | 46 | } |
|
59 | 60 | }) |
60 | 61 | } |
61 | 62 |
|
| 63 | + reset(){ |
| 64 | +if(this.worker){ |
| 65 | +this.worker.terminate() |
| 66 | +this.worker=null |
| 67 | +} |
| 68 | + this.standardIO.message('Worker process terminated.') |
| 69 | + this.initialiseWorker() |
| 70 | +} |
| 71 | + |
62 | 72 | handleStdinData(inputValue){ |
63 | 73 | if(this.stdinbuffer&&this.stdinbufferInt){ |
64 | 74 | letstartingIndex=1 |
|
92 | 102 | this.handleStdinData(inputValue) |
93 | 103 | }) |
94 | 104 | } else if (type === 'finished'){ |
95 | | -this.standardIO.stderr(`Exited with status:${event.data.returnCode}\r\n`) |
| 105 | +this.standardIO.message(`Exited with status:${event.data.returnCode}`) |
| 106 | +this.finishedCallback() |
96 | 107 | } |
97 | 108 | } |
98 | 109 | } |
|
168 | 179 | break; |
169 | 180 | case"\x7F":// BACKSPACE |
170 | 181 | case "\x08":// CTRL+H |
171 | | -case "\x04":// CTRL+D |
172 | 182 | this.handleCursorErase(true); |
173 | 183 | break; |
| 184 | +case "\x04":// CTRL+D |
| 185 | +// Send empty input |
| 186 | +if(this.input===''){ |
| 187 | +this.resolveInput('') |
| 188 | +this.activeInput=false; |
| 189 | +} |
174 | 190 | } |
175 | 191 | }else{ |
176 | 192 | this.handleCursorInsert(data); |
|
265 | 281 | } |
266 | 282 | } |
267 | 283 |
|
| 284 | +construnButton=document.getElementById('run') |
268 | 285 | constreplButton=document.getElementById('repl') |
| 286 | +conststopButton=document.getElementById('stop') |
269 | 287 | constclearButton=document.getElementById('clear') |
270 | 288 |
|
| 289 | +constcodeBox=document.getElementById('codebox') |
| 290 | + |
271 | 291 | window.onload=()=>{ |
272 | 292 | constterminal=newWasmTerminal() |
273 | 293 | terminal.open(document.getElementById('terminal')) |
|
277 | 297 | stderr:(charCode)=>{terminal.print(charCode)}, |
278 | 298 | stdin:async()=>{ |
279 | 299 | returnawaitterminal.prompt() |
| 300 | +}, |
| 301 | +message:(text)=>{terminal.writeLine(`\r\n${text}\r\n`)}, |
| 302 | +} |
| 303 | + |
| 304 | +constprogramRunning=(isRunning)=>{ |
| 305 | +if(isRunning){ |
| 306 | +replButton.setAttribute('disabled',true) |
| 307 | +runButton.setAttribute('disabled',true) |
| 308 | +stopButton.removeAttribute('disabled') |
| 309 | +}else{ |
| 310 | +replButton.removeAttribute('disabled') |
| 311 | +runButton.removeAttribute('disabled') |
| 312 | +stopButton.setAttribute('disabled',true) |
280 | 313 | } |
281 | 314 | } |
282 | 315 |
|
| 316 | +runButton.addEventListener('click',(e)=>{ |
| 317 | +terminal.clear() |
| 318 | +programRunning(true) |
| 319 | +constcode=codeBox.value |
| 320 | +pythonWorkerManager.run({args:['main.py'],files:{'main.py':code}}) |
| 321 | +}) |
| 322 | + |
283 | 323 | replButton.addEventListener('click',(e)=>{ |
| 324 | +terminal.clear() |
| 325 | +programRunning(true) |
284 | 326 | // Need to use "-i -" to force interactive mode. |
285 | 327 | // Looks like isatty always returns false in emscripten |
286 | 328 | pythonWorkerManager.run({args:['-i','-'],files:{}}) |
287 | 329 | }) |
288 | 330 |
|
| 331 | +stopButton.addEventListener('click',(e)=>{ |
| 332 | +programRunning(false) |
| 333 | +pythonWorkerManager.reset() |
| 334 | +}) |
| 335 | + |
289 | 336 | clearButton.addEventListener('click',(e)=>{ |
290 | 337 | terminal.clear() |
291 | 338 | }) |
292 | 339 |
|
293 | 340 | constreadyCallback=()=>{ |
294 | 341 | replButton.removeAttribute('disabled') |
| 342 | +runButton.removeAttribute('disabled') |
295 | 343 | clearButton.removeAttribute('disabled') |
296 | 344 | } |
297 | 345 |
|
298 | | -constpythonWorkerManager=newWorkerManager('./python.worker.js',stdio,readyCallback) |
| 346 | +constfinishedCallback=()=>{ |
| 347 | +programRunning(false) |
| 348 | +} |
| 349 | + |
| 350 | +constpythonWorkerManager=newWorkerManager('./python.worker.js',stdio,readyCallback,finishedCallback) |
299 | 351 | } |
300 | 352 | </script> |
301 | 353 | </head> |
302 | 354 | <body> |
303 | 355 | <h1>Simple REPL for Python WASM</h1> |
304 | | -<divid="terminal"></div> |
| 356 | +<textareaid="codebox"cols="108"rows="16"> |
| 357 | +print('Welcome to WASM!') |
| 358 | +</textarea> |
305 | 359 | <divclass="button-container"> |
| 360 | +<buttonid="run"disabled>Run</button> |
306 | 361 | <buttonid="repl"disabled>Start REPL</button> |
| 362 | +<buttonid="stop"disabled>Stop</button> |
307 | 363 | <buttonid="clear"disabled>Clear</button> |
308 | 364 | </div> |
| 365 | +<divid="terminal"></div> |
309 | 366 | <divid="info"> |
310 | 367 | The simple REPL provides a limited Python experience in the browser. |
311 | 368 | <ahref="https://github.com/python/cpython/blob/main/Tools/wasm/README.md"> |
|