8000 WIP: py-terminal plugin by antocuni · Pull Request #1771 · pyscript/pyscript · GitHub
[go: up one dir, main page]

Skip to content

WIP: py-terminal plugin #1771

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

Closed
wants to merge 13 commits into from
Closed
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
88 changes: 88 additions & 0 deletions pyscript.core/src/plugins/py-terminal.js
10000
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// PyScript py-terminal plugin
import { hooks } from "../core.js";

const makePyTerminal = async () => {
const element = document.querySelector("py-terminal");
if (element === null) {
// no py-terminal found, nothing to do
return false;
}

document
.getElementsByTagName("head")[0]
.insertAdjacentHTML(
"beforeend",
'<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.min.css">',
);
const { Terminal } = await import(
/* webpackIgnore: true */ "https://cdn.jsdelivr.net/npm/xterm@5.3.0/+esm"
);
const { Readline } = await import(
/* webpackIgnore: true */ "https://cdn.jsdelivr.net/npm/xterm-readline@1.1.1/+esm"
);

const term = new Terminal({
theme: {
background: "#191A19",
foreground: "#F5F2E7",
},
cursorBlink: true,
cursorStyle: "block",
rows: 50,
});

const rl = new Readline();
term.loadAddon(rl);
term.open(element);
term.focus();

async function pyterminal_readline(prompt) {
const line = await rl.read(prompt);
return line;
}

async function pyterminal_write(line) {
rl.write(line);
}

console.log("PyTerminal made?");
return { term, pyterminal_readline, pyterminal_write };
};

// this is ONLY for non-workers, correct?
// TODO: how to make it working for workers?
hooks.onInterpreterReady.add(async function override(pyScript) {
console.log("hello onInterpreterReady");
const t = await makePyTerminal();
if (!t) {
console.log("<py-terminal> not found, nothing to do");
return;
}
// XXX: we should investigate pyodide "write handler", it should be more
// efficient:
// https://pyodide.org/en/stable/usage/streams.html#a-write-handler
//
// Also: should the stdout/stderr go ALSO to the JS console?
function myStdout(byte) {
t.write(String.fromCharCode(byte));
}
const pyodide = pyScript.interpreter;
pyodide.setStdout({ raw: myStdout });
pyodide.setStderr({ raw: myStdout });
});

hooks.onWorkerReady.add(async function (_, xworker) {
console.log("hello onWorkerReady");
const t = await makePyTerminal();
if (!t) {
console.log("<py-terminal> not found, nothing to do");
return;
}
xworker.sync.pyterminal_readline = t.pyterminal_readline;
xworker.sync.pyterminal_write = t.pyterminal_write;
});

hooks.codeBeforeRunWorker.add(`
from pyscript import pyterminal
pyterminal.init()
`);
23 changes: 23 additions & 0 deletions pyscript.core/src/stdlib/pyscript/pyterminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import builtins
import sys

import js
from pyscript import sync


class PyTerminal:
def write(self, line):
sync.pyterminal_write(line)

def input(self, prompt):
return sync.pyterminal_readline(prompt)


PY_TERMINAL = None


def init():
global PY_TERMINAL
PY_TERMINAL = PyTerminal()
sys.stdout = sys.stderr = PY_TERMINAL
builtins.input = PY_TERMINAL.input
32 changes: 32 additions & 0 deletions pyscript.core/test/pyterminal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyScript Next</title>
<script>
addEventListener("py:ready", console.log);
</script>
<link rel="stylesheet" href="../dist/core.css">
<script type="module" src="../dist/core.js"></script>

</head>
<body>
<script type="py" worker>
import sys
from pyscript import display
display("Hello", "PyScript Next", append=False)
print("this should go to the terminal")
print("another line")

# XXX we have a problem with the error plugin: this line should
# just go to the terminal, NOT to the red box in the DOM
print("this goes to stderr", file=sys.stderr)

import code
code.interact()
</script>

<py-terminal></py-terminal>
</body>
</html>
7 changes: 4 additions & 3 deletions pyscript.core/types/plugins.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
declare namespace _default {
function error(): Promise<typeof import("./plugins/error.js")>;
}
declare const _default: {
error: () => Promise<typeof import("./plugins/error.js")>;
"py-terminal": () => Promise<typeof import("./plugins/py-terminal.js")>;
};
export default _default;
1 change: 1 addition & 0 deletions pyscript.core/types/plugins/py-terminal.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
1 change: 1 addition & 0 deletions pyscript.core/types/stdlib/pyscript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare namespace _default {
"display.py": string;
"event_handling.py": string;
"magic_js.py": string;
"pyterminal.py": string;
"util.py": string;
};
let pyweb: {
Expand Down
0