Fix MicroPython terminal input when no REPL is used/needed (#2113)

* Fix terminal input when no REPL is used/needed
* Fix input backspace too
This commit is contained in:
Andrea Giammarchi
2024-07-03 13:03:31 +02:00
committed by GitHub
parent 6f49f18937
commit 67d47511d5
7 changed files with 129 additions and 50 deletions

View File

@@ -1,12 +1,12 @@
{ {
"name": "@pyscript/core", "name": "@pyscript/core",
"version": "0.4.53", "version": "0.4.55",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@pyscript/core", "name": "@pyscript/core",
"version": "0.4.53", "version": "0.4.55",
"license": "APACHE-2.0", "license": "APACHE-2.0",
"dependencies": { "dependencies": {
"@ungap/with-resolvers": "^0.1.0", "@ungap/with-resolvers": "^0.1.0",
@@ -21,8 +21,8 @@
"@codemirror/lang-python": "^6.1.6", "@codemirror/lang-python": "^6.1.6",
"@codemirror/language": "^6.10.2", "@codemirror/language": "^6.10.2",
"@codemirror/state": "^6.4.1", "@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.28.2", "@codemirror/view": "^6.28.3",
"@playwright/test": "^1.45.0", "@playwright/test": "^1.45.1",
"@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-terser": "^0.4.4",
@@ -32,13 +32,13 @@
"bun": "^1.1.17", "bun": "^1.1.17",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"eslint": "^9.5.0", "eslint": "^9.6.0",
"flatted": "^3.3.1", "flatted": "^3.3.1",
"rollup": "^4.18.0", "rollup": "^4.18.0",
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string": "^3.0.0", "rollup-plugin-string": "^3.0.0",
"static-handler": "^0.4.3", "static-handler": "^0.4.3",
"typescript": "^5.5.2", "typescript": "^5.5.3",
"xterm": "^5.3.0", "xterm": "^5.3.0",
"xterm-readline": "^1.1.1" "xterm-readline": "^1.1.1"
} }
@@ -136,9 +136,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@codemirror/view": { "node_modules/@codemirror/view": {
"version": "6.28.2", "version": "6.28.3",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.2.tgz", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.3.tgz",
"integrity": "sha512-A3DmyVfjgPsGIjiJqM/zvODUAPQdQl3ci0ghehYNnbt5x+o76xq+dL5+mMBuysDXnI3kapgOkoeJ0sbtL/3qPw==", "integrity": "sha512-QVqP+ko078/h9yrW+u5grX3rQhC+BkGKADRrlDaJznfPngJOv5zObiVf0+SgAWhL/Yt0nvZ+10rO3L+gU5IbFw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -187,15 +187,15 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.16.0", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.16.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.0.tgz",
"integrity": "sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==", "integrity": "sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/object-schema": "^2.1.4", "@eslint/object-schema": "^2.1.4",
"debug": "^4.3.1", "debug": "^4.3.1",
"minimatch": "^3.0.5" "minimatch": "^3.1.2"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -226,9 +226,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.5.0", "version": "9.6.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.5.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz",
"integrity": "sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==", "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -585,13 +585,13 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.45.0", "version": "1.45.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.0.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.1.tgz",
"integrity": "sha512-TVYsfMlGAaxeUllNkywbwek67Ncf8FRGn8ZlRdO291OL3NjG9oMbfVhyP82HQF0CZLMrYsvesqoUekxdWuF9Qw==", "integrity": "sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.45.0" "playwright": "1.45.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -1752,17 +1752,17 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.5.0", "version": "9.6.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.5.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.6.0.tgz",
"integrity": "sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==", "integrity": "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/config-array": "^0.16.0", "@eslint/config-array": "^0.17.0",
"@eslint/eslintrc": "^3.1.0", "@eslint/eslintrc": "^3.1.0",
"@eslint/js": "9.5.0", "@eslint/js": "9.6.0",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.3.0", "@humanwhocodes/retry": "^0.3.0",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
@@ -1773,7 +1773,7 @@
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.0.1", "eslint-scope": "^8.0.1",
"eslint-visitor-keys": "^4.0.0", "eslint-visitor-keys": "^4.0.0",
"espree": "^10.0.1", "espree": "^10.1.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@@ -2882,13 +2882,13 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.45.0", "version": "1.45.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.0.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz",
"integrity": "sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==", "integrity": "sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.45.0" "playwright-core": "1.45.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -2901,9 +2901,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.45.0", "version": "1.45.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.0.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.1.tgz",
"integrity": "sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==", "integrity": "sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
@@ -4189,9 +4189,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.5.2", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz",
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@pyscript/core", "name": "@pyscript/core",
"version": "0.4.53", "version": "0.4.55",
"type": "module", "type": "module",
"description": "PyScript", "description": "PyScript",
"module": "./index.js", "module": "./index.js",
@@ -54,8 +54,8 @@
"@codemirror/lang-python": "^6.1.6", "@codemirror/lang-python": "^6.1.6",
"@codemirror/language": "^6.10.2", "@codemirror/language": "^6.10.2",
"@codemirror/state": "^6.4.1", "@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.28.2", "@codemirror/view": "^6.28.3",
"@playwright/test": "^1.45.0", "@playwright/test": "^1.45.1",
"@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-terser": "^0.4.4",
@@ -65,13 +65,13 @@
"bun": "^1.1.17", "bun": "^1.1.17",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"eslint": "^9.5.0", "eslint": "^9.6.0",
"flatted": "^3.3.1", "flatted": "^3.3.1",
"rollup": "^4.18.0", "rollup": "^4.18.0",
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string": "^3.0.0", "rollup-plugin-string": "^3.0.0",
"static-handler": "^0.4.3", "static-handler": "^0.4.3",
"typescript": "^5.5.2", "typescript": "^5.5.3",
"xterm": "^5.3.0", "xterm": "^5.3.0",
"xterm-readline": "^1.1.1" "xterm-readline": "^1.1.1"
}, },

View File

@@ -49,11 +49,12 @@ const workerReady = ({ interpreter, io, run, type }, { sync }) => {
const writer = encoder.writable.getWriter(); const writer = encoder.writable.getWriter();
sync.pyterminal_stream_write = (buffer) => writer.write(buffer); sync.pyterminal_stream_write = (buffer) => writer.write(buffer);
pyterminal_ready();
interpreter.replInit(); interpreter.replInit();
}, },
}); });
pyterminal_ready();
}; };
export default async (element) => { export default async (element) => {
@@ -163,7 +164,18 @@ export default async (element) => {
}; };
terminal.onData((buffer) => { terminal.onData((buffer) => {
if (promisedChunks) { if (promisedChunks) {
readChunks += buffer; // handle backspace on input
if (buffer === "\x7f") {
// avoid over-greedy backspace
if (readChunks.length) {
readChunks = readChunks.slice(0, -1);
// override previous char position
// put an empty space to clear the char
// move back position again
buffer = "\b \b";
} else buffer = "";
} else readChunks += buffer;
if (buffer) {
terminal.write(buffer); terminal.write(buffer);
if (readChunks.endsWith("\r")) { if (readChunks.endsWith("\r")) {
terminal.write("\n"); terminal.write("\n");
@@ -171,6 +183,7 @@ export default async (element) => {
promisedChunks = null; promisedChunks = null;
readChunks = ""; readChunks = "";
} }
}
} else { } else {
stream.write(buffer); stream.write(buffer);
} }

View File

@@ -9,7 +9,7 @@
<style>.xterm { padding: .5rem; }</style> <style>.xterm { padding: .5rem; }</style>
</head> </head>
<body> <body>
<script type="py" worker terminal> <script type="mpy" worker terminal>
from pyscript import document from pyscript import document
document.documentElement.classList.add("first") document.documentElement.classList.add("first")

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>
<a href="./no-repl.html">Prompt: NO REPL</a>
</li>
<li>
<a href="./repl.html">Prompt: REPL</a>
</li>
</ul>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyTerminal Prompt: NO REPL</title>
<script type="module" src="../../dist/core.js"></script>
<style>.xterm { padding: .5rem; }</style>
</head>
<body>
<script type="mpy" worker terminal>
prompt = input("Say something: ")
print("You said, ", prompt)
</script>
<script type="py" worker terminal>
prompt = input("Say something: ")
print("You said, ", prompt)
</script>
</body>
</html>

View File

@@ -0,0 +1,28 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyTerminal Prompt: REPL</title>
<script type="module" src="../../dist/core.js"></script>
<style>.xterm { padding: .5rem; }</style>
</head>
<body>
<script type="mpy" worker terminal>
import code
code.interact()
prompt = input("Say something: ")
print("You said, ", prompt)
</script>
<script type="py" worker terminal>
import code
code.interact()
# Pyodide won't execute this ... ever
# this should be tested manually
prompt = input("Say something: ")
print("You said, ", prompt)
</script>
</body>
</html>