Skip to content

Add interactive shell to WASM demo #643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion wasm/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Bindings to the RustPython library for WebAssembly",
"main": "index.js",
"dependencies": {
"codemirror": "^5.42.0"
"codemirror": "^5.42.0",
"xterm": "^3.8.0"
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "0.2.0",
Expand Down
3 changes: 3 additions & 0 deletions wasm/demo/src/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<h3>Standard Output</h3>
<textarea id="console" readonly>Loading...</textarea>

<h3>Interactive shell</h3>
<div id="terminal"></div>

<p>Here's some info regarding the <code>rp.pyEval()</code> function</p>
<ul>
<li>
Expand Down
1 change: 1 addition & 0 deletions wasm/demo/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import './style.css';
import 'codemirror/lib/codemirror.css';
import 'xterm/dist/xterm.css';

// A dependency graph that contains any wasm must all be imported
// asynchronously. This `index.js` file does the single async import, so
Expand Down
56 changes: 56 additions & 0 deletions wasm/demo/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as rp from '../../lib/pkg';
import CodeMirror from 'codemirror';
import 'codemirror/mode/python/python';
import 'codemirror/addon/comment/comment';
import { Terminal } from 'xterm';

// so people can play around with it
window.rp = rp;
Expand Down Expand Up @@ -72,3 +73,58 @@ snippets.addEventListener('change', updateSnippet);
// Run once for demo (updateSnippet b/c the browser might try to keep the same
// option selected for the `select`, but the textarea won't be updated)
updateSnippet();

const prompt = ">>>>> ";

const term = new Terminal();
term.open(document.getElementById('terminal'));
term.write(prompt);

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 terminalVM = rp.vmStore.init("term_vm");
terminalVM.setStdout(printToConsole);

var input = "";
term.on("data", (data) => {
const code = data.charCodeAt(0);
if (code == 13) { // CR
if (input[input.length - 1] == ':') {
Copy link
Member

@coolreader18 coolreader18 Mar 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use .trimEnd() here in case of spaces at the end of a line? Also, there might be a function that has multiple lines in its body, so it'd be good to keep a boolean of whether or not we're in a block and if so wait to end input until there's an empty line, a la CPython:

>>>>> def a():
.....     print('1')
.....     print('2')
..... 
>>>>>

Copy link
Contributor Author

@palaviv palaviv Mar 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to do this in a different PR. We currently don't support this in the REPL as well... (#626)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!

input += data
term.write("\r\n.....");
} else {
term.write("\r\n");
try {
terminalVM.exec(input);
} catch (err) {
if (err instanceof WebAssembly.RuntimeError) {
err = window.__RUSTPYTHON_ERROR || err;
}
printToConsole(err);
}
term.write(prompt);
input = "";
}
} else if (code == 127) {
if (input.length > 0) {
term.write("\b \b");
input = input.slice(0, -1);
}
} else if (code < 32 || code == 127) { // Control
return;
} else { // Visible
term.write(data);
input += data;
}
});