8000 a very hacky and very very tentative implementation sketchy implement… · pyscript/pyscript@82e733a · GitHub
[go: up one dir, main page]

Skip to content

Commit 82e733a

Browse files
committed
a very hacky and very very tentative implementation sketchy implementation of the py-terminal plugin
1 parent c6aaacd commit 82e733a

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// PyScript py-terminal plugin
2+
import { hooks } from "../core.js";
3+
4+
// XXX TODO:
5+
// 1. these imports should be lazy?
6+
// 2. would be nice to automatically add xterm.css on demand
7+
import { Terminal } from 'https://cdn.jsdelivr.net/npm/xterm@5.3.0/+esm'
8+
import { Readline } from 'https://cdn.jsdelivr.net/npm/xterm-readline@1.1.1/+esm'
9+
const makePyTerminal = () => {
10+
const element = document.querySelector('py-terminal');
11+
if (element === null) {
12+
return false;
13+
}
14+
15+
const term = new Terminal({
16+
theme: {
17+
background: "#191A19",
18+
foreground: "#F5F2E7",
19+
},
20+
cursorBlink: true,
21+
cursorStyle: "block",
22+
rows: 50
23+
});
24+
25+
const rl = new Readline();
26+
term.loadAddon(rl);
27+
term.open(element);
28+
term.focus();
29+
30+
async function readline(prompt) {
31+
//console.log("readline", prompt);
32+
const line = await rl.read(prompt);
33+
return line;
34+
}
35+
36+
async function write(line) {
37+
//console.log("write", line);
38+
rl.write(line);
39+
}
40+
41+
console.log("PyTerminal made?");
42+
return { term, readline, write };
43+
}
44+
45+
// this is ONLY for non-workers, correct?
46+
// TODO: how to make it working for workers?
47+
hooks.onInterpreterReady.add(function override(pyScript) {
48+
console.log("hello onInterpreterReady");
49+
const t = makePyTerminal();
50+
if (!t) {
51+
console.log("<py-terminal> not found, nothing to do");
52+
return;
53+
}
54+
const { stdout, stderr } = pyScript.io;
55+
56+
pyScript.io.stdout = (s, ...rest) => {
57+
// XXX: the + "\n" is conceptually wrong.
58+
// We probably need to configure pyodide's stdout as "raw mode"
59+
// instead of "batched mode":
60+
// https://pyodide.org/en/stable/usage/streams.html#a-raw-handler
61+
t.write(s + "\n");
62+
stdout(s, ...rest);
63+
}
64+
65+
pyScript.io.stderr = (s, ...rest) => {
66+
t.write(s + "\n"); // see above for the "\n"
67+
stderr(s, ...rest);
68+
}
69+
});
70+
71+
72+
// this is mostly pseudo-code for what it *should* happen for the workers case
73+
/*
74+
addEventListener("py:ready", (event) => {
75+
console.log("hello py:ready");
76+
if (!event.detail.worker) {
77+
return;
78+
}
79+
80+
const t = makePyTerminal();
81+
if (!t) {
82+
console.log("<py-terminal> not found, nothing to do");
83+
return;
84+
}
85+
86+
const xworker = event.target.xworker;
87+
88+
xworker.sync.pyterminal_readline = t.readline;
89+
xworker.sync.pyterminal_write = t.write;
90+
91+
// XXX: I know that the following lines don't work, but this is more or
92+
// lesswhat I would like to happen
93+
pyScript.io.stdout = (s, ...rest) => {
94+
// this is JS code, and we cannot send arbitrary JS code from the main
95+
// to the worker. So maybe a solution is to hardcode this logic
96+
// directly inside the worker code?
97+
xworker.sync.pyterminal_write(s);
98+
}
99+
pyScript.io.stderr = (s, ...rest) => {
100+
xworker.sync.pyterminal_write(s);
101+
}
102+
something.runPython(`
103+
import builtins
104+
import pyscript
105+
builtins.input = sync.pyterminal_readline
106+
`)
107+
108+
});
109+
*/

pyscript.core/test/pyterminal.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>PyScript Next</title>
7+
<script>
8+
addEventListener("py:ready", console.log);
9+
</script>
10+
<link rel="stylesheet" href="../dist/core.css">
11+
<script type="module" src="../dist/core.js"></script>
12+
13+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.2.1/css/xterm.min.css">
14+
15+
</head>
16+
<body>
17+
<script type="py">
18+
import sys
19+
from pyscript import display
20+
C5DD display("Hello", "PyScript Next", append=False)
21+
print("this should go to the terminal")
22+
print("another line")
23+
24+
# XXX we have a problem with the error plugin: this line should
25+
# just go to the terminal, NOT to the red box in the DOM
26+
print("this goes to stderr", file=sys.stderr)
27+
</script>
28+
29+
<py-terminal></py-terminal>
30+
</body>
31+
</html>

pyscript.core/types/plugins.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
declare namespace _default {
22
function error(): Promise<typeof import("./plugins/error.js")>;
3+
function pyterminal(): Promise<typeof import("./plugins/pyterminal.js")>;
34
}
45
export default _default;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

0 commit comments

Comments
 (0)
0