Spaces:
Running
Running
File size: 5,675 Bytes
a0762a6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/jquery"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery.terminal@2.23.0/js/jquery.terminal.min.js"></script>
<link
href="https://cdn.jsdelivr.net/npm/jquery.terminal@2.23.0/css/jquery.terminal.min.css"
rel="stylesheet"
/>
<script src="./pyodide.js"></script>
<style>
.terminal {
--size: 1.5;
--color: rgba(255, 255, 255, 0.8);
}
</style>
</head>
<body>
<script>
"use strict";
function sleep(s) {
return new Promise((resolve) => setTimeout(resolve, s));
}
async function main() {
globalThis.pyodide = await loadPyodide({
indexURL: "./",
});
let namespace = pyodide.globals.get("dict")();
pyodide.runPython(
`
import sys
from pyodide import to_js
from pyodide.console import PyodideConsole, repr_shorten, BANNER
import __main__
BANNER = "Welcome to the Pyodide terminal emulator π\\n" + BANNER
pyconsole = PyodideConsole(__main__.__dict__)
import builtins
async def await_fut(fut):
res = await fut
if res is not None:
builtins._ = res
return to_js([res], depth=1)
def clear_console():
pyconsole.buffer = []
`,
namespace
);
let repr_shorten = namespace.get("repr_shorten");
let banner = namespace.get("BANNER");
let await_fut = namespace.get("await_fut");
let pyconsole = namespace.get("pyconsole");
let clear_console = namespace.get("clear_console");
namespace.destroy();
let ps1 = ">>> ",
ps2 = "... ";
async function lock() {
let resolve;
let ready = term.ready;
term.ready = new Promise((res) => (resolve = res));
await ready;
return resolve;
}
async function interpreter(command) {
let unlock = await lock();
term.pause();
// multiline should be splitted (useful when pasting)
for (const c of command.split("\n")) {
let fut = pyconsole.push(c);
term.set_prompt(fut.syntax_check === "incomplete" ? ps2 : ps1);
switch (fut.syntax_check) {
case "syntax-error":
term.error(fut.formatted_error.trimEnd());
continue;
case "incomplete":
continue;
case "complete":
break;
default:
throw new Error(`Unexpected type ${ty}`);
}
// In JavaScript, await automatically also awaits any results of
// awaits, so if an async function returns a future, it will await
// the inner future too. This is not what we want so we
// temporarily put it into a list to protect it.
let wrapped = await_fut(fut);
// complete case, get result / error and print it.
try {
let [value] = await wrapped;
if (value !== undefined) {
term.echo(
repr_shorten.callKwargs(value, {
separator: "\n[[;orange;]<long output truncated>]\n",
})
);
}
if (pyodide.isPyProxy(value)) {
value.destroy();
}
} catch (e) {
if (e.constructor.name === "PythonError") {
const message = fut.formatted_error || e.message;
term.error(message.trimEnd());
} else {
throw e;
}
} finally {
fut.destroy();
wrapped.destroy();
}
}
term.resume();
await sleep(10);
unlock();
}
let term = $("body").terminal(interpreter, {
greetings: banner,
prompt: ps1,
completionEscape: false,
completion: function (command, callback) {
callback(pyconsole.complete(command).toJs()[0]);
},
keymap: {
"CTRL+C": async function (event, original) {
clear_console();
term.echo_command();
term.echo("KeyboardInterrupt");
term.set_command("");
term.set_prompt(ps1);
},
TAB: (event, original) => {
const command = term.before_cursor();
// Disable completion for whitespaces.
if (command.trim() === "") {
term.insert("\t");
return false;
}
return original(event);
},
},
});
window.term = term;
pyconsole.stdout_callback = (s) => term.echo(s, { newline: false });
pyconsole.stderr_callback = (s) => {
term.error(s.trimEnd());
};
term.ready = Promise.resolve();
pyodide._module.on_fatal = async (e) => {
term.error(
"Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."
);
term.error("The cause of the fatal error was:");
term.error(e);
term.error("Look in the browser console for more details.");
await term.ready;
term.pause();
await sleep(15);
term.pause();
};
}
window.console_ready = main();
</script>
</body>
</html>
|