Skip to content

Commit df6acaf

Browse files
Merge pull request #1439 from RustPython/coolreader18/xterm-local-echo
Improve the demo terminal's navigation
2 parents 0d9e723 + 2160f68 commit df6acaf

2 files changed

Lines changed: 33 additions & 69 deletions

File tree

wasm/demo/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"main": "index.js",
66
"dependencies": {
77
"codemirror": "^5.42.0",
8+
"local-echo": "^0.2.0",
89
"xterm": "^3.8.0"
910
},
1011
"devDependencies": {
@@ -14,11 +15,11 @@
1415
"html-webpack-plugin": "^3.2.0",
1516
"mini-css-extract-plugin": "^0.5.0",
1617
"raw-loader": "^1.0.0",
18+
"serve": "^11.0.2",
19+
"start-server-and-test": "^1.7.11",
1720
"webpack": "^4.16.3",
1821
"webpack-cli": "^3.1.0",
19-
"webpack-dev-server": "^3.1.5",
20-
"start-server-and-test": "^1.7.11",
21-
"serve": "^11.0.2"
22+
"webpack-dev-server": "^3.1.5"
2223
},
2324
"scripts": {
2425
"dev": "webpack-dev-server -d",

wasm/demo/src/main.js

Lines changed: 29 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import CodeMirror from 'codemirror';
33
import 'codemirror/mode/python/python';
44
import 'codemirror/addon/comment/comment';
55
import { Terminal } from 'xterm';
6+
import LocalEchoController from 'local-echo';
67

78
// so people can play around with it
89
window.rp = rp;
@@ -35,7 +36,7 @@ function runCodeFromTextarea() {
3536

3637
const code = editor.getValue();
3738
try {
38-
const result = rp.pyEval(code, {
39+
rp.pyEval(code, {
3940
stdout: output => {
4041
const shouldScroll =
4142
consoleElement.scrollHeight - consoleElement.scrollTop ===
@@ -46,9 +47,6 @@ function runCodeFromTextarea() {
4647
}
4748
}
4849
});
49-
if (result !== null) {
50-
consoleElement.value += `\n${result}\n`;
51-
}
5250
} catch (err) {
5351
if (err instanceof WebAssembly.RuntimeError) {
5452
err = window.__RUSTPYTHON_ERROR || err;
@@ -82,24 +80,16 @@ snippets.addEventListener('change', updateSnippet);
8280
// option selected for the `select`, but the textarea won't be updated)
8381
updateSnippet();
8482

85-
function removeNonAscii(str) {
86-
if (str === null || str === '') return false;
87-
else str = str.toString();
88-
89-
return str.replace(/[^\x20-\x7E]/g, '');
90-
}
91-
92-
function printToConsole(data) {
93-
term.write(removeNonAscii(data) + '\r\n');
94-
}
95-
9683
const term = new Terminal();
9784
term.open(document.getElementById('terminal'));
9885

86+
const localEcho = new LocalEchoController(term);
87+
9988
const terminalVM = rp.vmStore.init('term_vm');
100-
terminalVM.setStdout(printToConsole);
10189

102-
function getPrompt(name = 'ps1') {
90+
terminalVM.setStdout(data => localEcho.println(data));
91+
92+
function getPrompt(name) {
10393
terminalVM.exec(`
10494
try:
10595
import sys as __sys
@@ -112,64 +102,37 @@ finally:
112102
return String(terminalVM.eval('__prompt'));
113103
}
114104

115-
term.write(getPrompt());
105+
async function readPrompts() {
106+
let continuing = false;
116107

117-
function resetInput() {
118-
continuedInput = [];
119-
input = '';
120-
continuing = false;
121-
}
122-
123-
let continuedInput, input, continuing;
124-
resetInput();
125-
126-
let ps2;
127-
128-
term.on('data', data => {
129-
const code = data.charCodeAt(0);
130-
if (code == 13) {
131-
// CR
132-
term.write('\r\n');
133-
continuedInput.push(input);
108+
while (true) {
109+
const ps1 = getPrompt('ps1');
110+
const ps2 = getPrompt('ps2');
111+
let input;
134112
if (continuing) {
135-
if (input === '') {
136-
continuing = false;
137-
} else {
138-
input = '';
139-
term.write(ps2);
140-
return;
141-
}
113+
const prom = localEcho.read(ps2, ps2);
114+
localEcho._activePrompt.prompt = ps1;
115+
localEcho._input = localEcho.history.entries.pop() + '\n';
116+
localEcho._cursor = localEcho._input.length;
117+
localEcho._active = true;
118+
input = await prom;
119+
if (!input.endsWith('\n')) continue;
120+
} else {
121+
input = await localEcho.read(ps1, ps2);
142122
}
143123
try {
144-
terminalVM.execSingle(continuedInput.join('\n'));
124+
terminalVM.execSingle(input);
145125
} catch (err) {
146126
if (err instanceof SyntaxError && err.message.includes('EOF')) {
147-
ps2 = getPrompt('ps2');
148-
term.write(ps2);
149127
continuing = true;
150-
input = '';
151-
return;
128+
continue;
152129
} else if (err instanceof WebAssembly.RuntimeError) {
153130
err = window.__RUSTPYTHON_ERROR || err;
154131
}
155-
printToConsole(err);
132+
localEcho.println(err);
156133
}
157-
resetInput();
158-
term.write(getPrompt());
159-
} else if (code == 127 || code == 8) {
160-
// Backspace
161-
if (input.length > 0) {
162-
term.write('\b \b');
163-
input = input.slice(0, -1);
164-
}
165-
} else if (code < 32) {
166-
// Control
167-
term.write('\r\n' + getPrompt());
168-
input = '';
169-
continuedInput = [];
170-
} else {
171-
// Visible
172-
term.write(data);
173-
input += data;
134+
continuing = false;
174135
}
175-
});
136+
}
137+
138+
readPrompts().catch(err => console.error(err));

0 commit comments

Comments
 (0)