Skip to content

Commit 96dfaa0

Browse files
committed
Combine index.js and main.js into one to improve UX while loading rustpython
1 parent 73b363d commit 96dfaa0

File tree

2 files changed

+147
-145
lines changed

2 files changed

+147
-145
lines changed

wasm/demo/src/index.js

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,151 @@
11
import './style.css';
2-
import 'codemirror/lib/codemirror.css';
32
import 'xterm/lib/xterm.css';
3+
import CodeMirror from 'codemirror';
4+
import 'codemirror/mode/python/python';
5+
import 'codemirror/addon/comment/comment';
6+
import 'codemirror/lib/codemirror.css';
7+
import { Terminal } from 'xterm';
8+
import LocalEchoController from 'local-echo';
9+
10+
let rp;
411

5-
// A dependency graph that contains any wasm must all be imported
6-
// asynchronously. This `index.js` file does the single async import, so
7-
// that no one else needs to worry about it again.
8-
import('./main.js').catch(e => {
9-
console.error('Error importing `main.js`:', e);
10-
document.getElementById('error').textContent = e;
12+
// A dependency graph that contains any wasm must be imported asynchronously.
13+
import('rustpython')
14+
.then(rustpy => {
15+
rp = rustpy;
16+
// so people can play around with it
17+
window.rp = rustpy;
18+
onReady();
19+
})
20+
.catch(e => {
21+
console.error('Error importing `rustpython`:', e);
22+
document.getElementById('error').textContent = e;
23+
});
24+
25+
const editor = CodeMirror.fromTextArea(document.getElementById('code'), {
26+
extraKeys: {
27+
'Ctrl-Enter': runCodeFromTextarea,
28+
'Cmd-Enter': runCodeFromTextarea,
29+
'Shift-Tab': 'indentLess',
30+
'Ctrl-/': 'toggleComment',
31+
'Cmd-/': 'toggleComment',
32+
Tab: editor => {
33+
var spaces = Array(editor.getOption('indentUnit') + 1).join(' ');
34+
editor.replaceSelection(spaces);
35+
}
36+
},
37+
lineNumbers: true,
38+
mode: 'text/x-python',
39+
indentUnit: 4,
40+
autofocus: true
1141
});
42+
43+
const consoleElement = document.getElementById('console');
44+
const errorElement = document.getElementById('error');
45+
46+
function runCodeFromTextarea() {
47+
// Clean the console and errors
48+
consoleElement.value = '';
49+
errorElement.textContent = '';
50+
51+
const code = editor.getValue();
52+
try {
53+
rp.pyExec(code, {
54+
stdout: output => {
55+
const shouldScroll =
56+
consoleElement.scrollHeight - consoleElement.scrollTop ===
57+
consoleElement.clientHeight;
58+
consoleElement.value += output;
59+
if (shouldScroll) {
60+
consoleElement.scrollTop = consoleElement.scrollHeight;
61+
}
62+
}
63+
});
64+
} catch (err) {
65+
if (err instanceof WebAssembly.RuntimeError) {
66+
err = window.__RUSTPYTHON_ERROR || err;
67+
}
68+
errorElement.textContent = err;
69+
console.error(err);
70+
}
71+
}
72+
73+
const snippets = document.getElementById('snippets');
74+
75+
function updateSnippet() {
76+
const selected = snippets.value;
77+
78+
// the require here creates a webpack context; it's fine to use it
79+
// dynamically.
80+
// https://webpack.js.org/guides/dependency-management/
81+
const snippet = require(`raw-loader!../snippets/${selected}.py`);
82+
83+
editor.setValue(snippet);
84+
runCodeFromTextarea();
85+
}
86+
87+
const term = new Terminal();
88+
term.open(document.getElementById('terminal'));
89+
90+
const localEcho = new LocalEchoController(term);
91+
92+
let terminalVM;
93+
94+
function getPrompt(name) {
95+
terminalVM.exec(`
96+
try:
97+
import sys as __sys
98+
__prompt = __sys.${name}
99+
except:
100+
__prompt = ''
101+
finally:
102+
del __sys
103+
`);
104+
return String(terminalVM.eval('__prompt'));
105+
}
106+
107+
async function readPrompts() {
108+
let continuing = false;
109+
110+
while (true) {
111+
const ps1 = getPrompt('ps1');
112+
const ps2 = getPrompt('ps2');
113+
let input;
114+
if (continuing) {
115+
const prom = localEcho.read(ps2, ps2);
116+
localEcho._activePrompt.prompt = ps1;
117+
localEcho._input = localEcho.history.entries.pop() + '\n';
118+
localEcho._cursor = localEcho._input.length;
119+
localEcho._active = true;
120+
input = await prom;
121+
if (!input.endsWith('\n')) continue;
122+
} else {
123+
input = await localEcho.read(ps1, ps2);
124+
}
125+
try {
126+
terminalVM.execSingle(input);
127+
} catch (err) {
128+
if (err instanceof SyntaxError && err.message.includes('EOF')) {
129+
continuing = true;
130+
continue;
131+
} else if (err instanceof WebAssembly.RuntimeError) {
132+
err = window.__RUSTPYTHON_ERROR || err;
133+
}
134+
localEcho.println(err);
135+
}
136+
continuing = false;
137+
}
138+
}
139+
140+
function onReady() {
141+
snippets.addEventListener('change', updateSnippet);
142+
document
143+
.getElementById('run-btn')
144+
.addEventListener('click', runCodeFromTextarea);
145+
// Run once for demo
146+
runCodeFromTextarea();
147+
148+
terminalVM = rp.vmStore.init('term_vm');
149+
terminalVM.setStdout(data => localEcho.println(data));
150+
readPrompts().catch(err => console.error(err));
151+
}

wasm/demo/src/main.js

Lines changed: 0 additions & 138 deletions
This file was deleted.

0 commit comments

Comments
 (0)