mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 18:55:29 -05:00
Add REPL plugin hooks; Add output, output-mode, stderr attributes (#1106)
* Add before, after REPL hooks * Re-introduce 'output-mode' attribute for py-repl * Add plugin execution tests * Documentation * Changelog --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: mariana <marianameireles@protonmail.com>
This commit is contained in:
@@ -7,14 +7,16 @@ import { defaultKeymap } from '@codemirror/commands';
|
||||
import { oneDarkTheme } from '@codemirror/theme-one-dark';
|
||||
|
||||
import { getAttribute, ensureUniqueId, htmlDecode } from '../utils';
|
||||
import { pyExec, pyDisplay } from '../pyexec';
|
||||
import { pyExec } from '../pyexec';
|
||||
import { getLogger } from '../logger';
|
||||
import { InterpreterClient } from '../interpreter_client';
|
||||
import type { PyScriptApp } from '../main';
|
||||
import { Stdio } from '../stdio';
|
||||
|
||||
const logger = getLogger('py-repl');
|
||||
const RUNBUTTON = `<svg style="height:20px;width:20px;vertical-align:-.125em;transform-origin:center;overflow:visible;color:green" viewBox="0 0 384 512" aria-hidden="true" role="img" xmlns="http://www.w3.org/2000/svg"><g transform="translate(192 256)" transform-origin="96 0"><g transform="translate(0,0) scale(1,1)"><path d="M361 215C375.3 223.8 384 239.3 384 256C384 272.7 375.3 288.2 361 296.1L73.03 472.1C58.21 482 39.66 482.4 24.52 473.9C9.377 465.4 0 449.4 0 432V80C0 62.64 9.377 46.63 24.52 38.13C39.66 29.64 58.21 29.99 73.03 39.04L361 215z" fill="currentColor" transform="translate(-192 -256)"></path></g></g></svg>`;
|
||||
|
||||
export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
export function make_PyRepl(interpreter: InterpreterClient, app: PyScriptApp) {
|
||||
/* High level structure of py-repl DOM, and the corresponding JS names.
|
||||
|
||||
this <py-repl>
|
||||
@@ -31,6 +33,8 @@ export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
shadow: ShadowRoot;
|
||||
outDiv: HTMLElement;
|
||||
editor: EditorView;
|
||||
stdout_manager: Stdio | null;
|
||||
stderr_manager: Stdio | null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -152,27 +156,19 @@ export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
*/
|
||||
async execute(): Promise<void> {
|
||||
const pySrc = this.getPySrc();
|
||||
|
||||
// determine the output element
|
||||
const outEl = this.getOutputElement();
|
||||
if (outEl === undefined) {
|
||||
// this happens if we specified output="..." but we couldn't
|
||||
// find the ID. We already displayed an error message inside
|
||||
// getOutputElement, stop the execution.
|
||||
return;
|
||||
}
|
||||
|
||||
// clear the old output before executing the new code
|
||||
outEl.innerHTML = '';
|
||||
const outEl = this.outDiv;
|
||||
|
||||
// execute the python code
|
||||
app.plugins.beforePyReplExec({ interpreter: interpreter, src: pySrc, outEl: outEl, pyReplTag: this });
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const pyResult = (await pyExec(interpreter, pySrc, outEl)).result;
|
||||
|
||||
// display the value of the last evaluated expression (REPL-style)
|
||||
if (pyResult !== undefined) {
|
||||
pyDisplay(interpreter, pyResult, { target: outEl.id });
|
||||
}
|
||||
app.plugins.afterPyReplExec({
|
||||
interpreter: interpreter,
|
||||
src: pySrc,
|
||||
outEl: outEl,
|
||||
pyReplTag: this,
|
||||
result: pyResult, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
|
||||
});
|
||||
|
||||
this.autogenerateMaybe();
|
||||
}
|
||||
@@ -181,21 +177,6 @@ export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
return this.editor.state.doc.toString();
|
||||
}
|
||||
|
||||
getOutputElement(): HTMLElement {
|
||||
const outputID = getAttribute(this, 'output');
|
||||
if (outputID !== null) {
|
||||
const el = document.getElementById(outputID);
|
||||
if (el === null) {
|
||||
const err = `py-repl ERROR: cannot find the output element #${outputID} in the DOM`;
|
||||
this.outDiv.innerText = err;
|
||||
return undefined;
|
||||
}
|
||||
return el;
|
||||
} else {
|
||||
return this.outDiv;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX the autogenerate logic is very messy. We should redo it, and it
|
||||
// should be the default.
|
||||
autogenerateMaybe(): void {
|
||||
@@ -206,7 +187,15 @@ export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
const nextExecId = parseInt(lastExecId) + 1;
|
||||
|
||||
const newPyRepl = document.createElement('py-repl');
|
||||
newPyRepl.setAttribute('root', this.getAttribute('root'));
|
||||
|
||||
//Attributes to be copied from old REPL to auto-generated REPL
|
||||
for (const attribute of ['root', 'output-mode', 'output', 'stderr']) {
|
||||
const attr = getAttribute(this, attribute);
|
||||
if (attr) {
|
||||
newPyRepl.setAttribute(attribute, attr);
|
||||
}
|
||||
}
|
||||
|
||||
newPyRepl.id = this.getAttribute('root') + '-' + nextExecId.toString();
|
||||
|
||||
if (this.hasAttribute('auto-generate')) {
|
||||
@@ -214,20 +203,6 @@ export function make_PyRepl(interpreter: InterpreterClient) {
|
||||
this.removeAttribute('auto-generate');
|
||||
}
|
||||
|
||||
const outputMode = getAttribute(this, 'output-mode');
|
||||
if (outputMode) {
|
||||
newPyRepl.setAttribute('output-mode', outputMode);
|
||||
}
|
||||
|
||||
const addReplAttribute = (attribute: string) => {
|
||||
const attr = getAttribute(this, attribute);
|
||||
if (attr) {
|
||||
newPyRepl.setAttribute(attribute, attr);
|
||||
}
|
||||
};
|
||||
|
||||
addReplAttribute('output');
|
||||
|
||||
newPyRepl.setAttribute('exec-id', nextExecId.toString());
|
||||
if (this.parentElement) {
|
||||
this.parentElement.appendChild(newPyRepl);
|
||||
|
||||
Reference in New Issue
Block a user