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:
Jeff Glass
2023-03-22 20:19:22 -05:00
committed by GitHub
parent 51d51409d3
commit ef793aecf3
10 changed files with 514 additions and 91 deletions

View File

@@ -1,7 +1,10 @@
import { Plugin } from '../plugin';
import { TargetedStdio, StdioMultiplexer } from '../stdio';
import type { InterpreterClient } from '../interpreter_client';
import { createSingularWarning } from '../utils';
import { make_PyScript } from '../components/pyscript';
import { InterpreterClient } from '../interpreter_client';
import { pyDisplay } from '../pyexec';
import { make_PyRepl } from '../components/pyrepl';
type PyScriptTag = InstanceType<ReturnType<typeof make_PyScript>>;
@@ -58,4 +61,71 @@ export class StdioDirector extends Plugin {
options.pyScriptTag.stderr_manager = null;
}
}
beforePyReplExec(options: {
interpreter: InterpreterClient;
src: string;
outEl: HTMLElement;
pyReplTag: InstanceType<ReturnType<typeof make_PyRepl>>;
}): void {
//Handle 'output-mode' attribute (removed in PR #881/f9194cc8, restored here)
//If output-mode == 'append', don't clear target tag before writing
if (options.pyReplTag.getAttribute('output-mode') != 'append') {
options.outEl.innerHTML = '';
}
// Handle 'output' attribute; defaults to writing stdout to the existing outEl
// If 'output' attribute is used, the DOM element with the specified ID receives
// -both- sys.stdout and sys.stderr
let output_targeted_io: TargetedStdio;
if (options.pyReplTag.hasAttribute('output')) {
output_targeted_io = new TargetedStdio(options.pyReplTag, 'output', true, true);
} else {
output_targeted_io = new TargetedStdio(options.pyReplTag.outDiv, 'id', true, true);
}
options.pyReplTag.stdout_manager = output_targeted_io;
this._stdioMultiplexer.addListener(output_targeted_io);
//Handle 'stderr' attribute;
if (options.pyReplTag.hasAttribute('stderr')) {
const stderr_targeted_io = new TargetedStdio(options.pyReplTag, 'stderr', false, true);
options.pyReplTag.stderr_manager = stderr_targeted_io;
this._stdioMultiplexer.addListener(stderr_targeted_io);
}
}
afterPyReplExec(options: {
interpreter: InterpreterClient;
src: string;
outEl: HTMLElement;
pyReplTag: InstanceType<ReturnType<typeof make_PyRepl>>;
result: any; // eslint-disable-line @typescript-eslint/no-explicit-any
}): void {
// display the value of the last-evaluated expression in the REPL
if (options.result !== undefined) {
const outputId: string | undefined = options.pyReplTag.getAttribute('output');
if (outputId) {
// 'output' attribute also used as location to send
// result of REPL
if (document.getElementById(outputId)) {
pyDisplay(options.interpreter, options.result, { target: outputId });
} else {
//no matching element on page
createSingularWarning(`output = "${outputId}" does not match the id of any element on the page.`);
}
} else {
// 'otuput atribuite not provided
pyDisplay(options.interpreter, options.result, { target: options.outEl.id });
}
}
if (options.pyReplTag.stdout_manager != null) {
this._stdioMultiplexer.removeListener(options.pyReplTag.stdout_manager);
options.pyReplTag.stdout_manager = null;
}
if (options.pyReplTag.stderr_manager != null) {
this._stdioMultiplexer.removeListener(options.pyReplTag.stderr_manager);
options.pyReplTag.stderr_manager = null;
}
}
}