diff --git a/wasm/demo/package.json b/wasm/demo/package.json index a221ea275..2b6dd27fa 100644 --- a/wasm/demo/package.json +++ b/wasm/demo/package.json @@ -5,6 +5,7 @@ "main": "index.js", "dependencies": { "codemirror": "^5.42.0", + "local-echo": "^0.2.0", "xterm": "^3.8.0" }, "devDependencies": { @@ -14,11 +15,11 @@ "html-webpack-plugin": "^3.2.0", "mini-css-extract-plugin": "^0.5.0", "raw-loader": "^1.0.0", + "serve": "^11.0.2", + "start-server-and-test": "^1.7.11", "webpack": "^4.16.3", "webpack-cli": "^3.1.0", - "webpack-dev-server": "^3.1.5", - "start-server-and-test": "^1.7.11", - "serve": "^11.0.2" + "webpack-dev-server": "^3.1.5" }, "scripts": { "dev": "webpack-dev-server -d", diff --git a/wasm/demo/src/main.js b/wasm/demo/src/main.js index 590544199..48587640b 100644 --- a/wasm/demo/src/main.js +++ b/wasm/demo/src/main.js @@ -3,6 +3,7 @@ import CodeMirror from 'codemirror'; import 'codemirror/mode/python/python'; import 'codemirror/addon/comment/comment'; import { Terminal } from 'xterm'; +import LocalEchoController from 'local-echo'; // so people can play around with it window.rp = rp; @@ -35,7 +36,7 @@ function runCodeFromTextarea() { const code = editor.getValue(); try { - const result = rp.pyEval(code, { + rp.pyEval(code, { stdout: output => { const shouldScroll = consoleElement.scrollHeight - consoleElement.scrollTop === @@ -46,9 +47,6 @@ function runCodeFromTextarea() { } } }); - if (result !== null) { - consoleElement.value += `\n${result}\n`; - } } catch (err) { if (err instanceof WebAssembly.RuntimeError) { err = window.__RUSTPYTHON_ERROR || err; @@ -82,24 +80,16 @@ snippets.addEventListener('change', updateSnippet); // option selected for the `select`, but the textarea won't be updated) updateSnippet(); -function removeNonAscii(str) { - if (str === null || str === '') return false; - else str = str.toString(); - - return str.replace(/[^\x20-\x7E]/g, ''); -} - -function printToConsole(data) { - term.write(removeNonAscii(data) + '\r\n'); -} - const term = new Terminal(); term.open(document.getElementById('terminal')); -const terminalVM = rp.vmStore.init('term_vm'); -terminalVM.setStdout(printToConsole); +const localEcho = new LocalEchoController(term); -function getPrompt(name = 'ps1') { +const terminalVM = rp.vmStore.init('term_vm'); + +terminalVM.setStdout(data => localEcho.println(data)); + +function getPrompt(name) { terminalVM.exec(` try: import sys as __sys @@ -112,64 +102,37 @@ finally: return String(terminalVM.eval('__prompt')); } -term.write(getPrompt()); +async function readPrompts() { + let continuing = false; -function resetInput() { - continuedInput = []; - input = ''; - continuing = false; -} - -let continuedInput, input, continuing; -resetInput(); - -let ps2; - -term.on('data', data => { - const code = data.charCodeAt(0); - if (code == 13) { - // CR - term.write('\r\n'); - continuedInput.push(input); + while (true) { + const ps1 = getPrompt('ps1'); + const ps2 = getPrompt('ps2'); + let input; if (continuing) { - if (input === '') { - continuing = false; - } else { - input = ''; - term.write(ps2); - return; - } + const prom = localEcho.read(ps2, ps2); + localEcho._activePrompt.prompt = ps1; + localEcho._input = localEcho.history.entries.pop() + '\n'; + localEcho._cursor = localEcho._input.length; + localEcho._active = true; + input = await prom; + if (!input.endsWith('\n')) continue; + } else { + input = await localEcho.read(ps1, ps2); } try { - terminalVM.execSingle(continuedInput.join('\n')); + terminalVM.execSingle(input); } catch (err) { if (err instanceof SyntaxError && err.message.includes('EOF')) { - ps2 = getPrompt('ps2'); - term.write(ps2); continuing = true; - input = ''; - return; + continue; } else if (err instanceof WebAssembly.RuntimeError) { err = window.__RUSTPYTHON_ERROR || err; } - printToConsole(err); + localEcho.println(err); } - resetInput(); - term.write(getPrompt()); - } else if (code == 127 || code == 8) { - // Backspace - if (input.length > 0) { - term.write('\b \b'); - input = input.slice(0, -1); - } - } else if (code < 32) { - // Control - term.write('\r\n' + getPrompt()); - input = ''; - continuedInput = []; - } else { - // Visible - term.write(data); - input += data; + continuing = false; } -}); +} + +readPrompts().catch(err => console.error(err));