mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #654 from coolreader18/wasm-explicit-stdout
[WASM] Make setStdout arguments more explicit in what they print to
This commit is contained in:
@@ -36,7 +36,15 @@ function runCodeFromTextarea() {
|
||||
const code = editor.getValue();
|
||||
try {
|
||||
const result = rp.pyEval(code, {
|
||||
stdout: '#console'
|
||||
stdout: output => {
|
||||
const shouldScroll =
|
||||
consoleElement.scrollHeight - consoleElement.scrollTop ===
|
||||
consoleElement.clientHeight;
|
||||
consoleElement.value += output;
|
||||
if (shouldScroll) {
|
||||
consoleElement.scrollTop = consoleElement.scrollHeight;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result !== null) {
|
||||
consoleElement.value += `\n${result}\n`;
|
||||
@@ -74,57 +82,58 @@ snippets.addEventListener('change', updateSnippet);
|
||||
// option selected for the `select`, but the textarea won't be updated)
|
||||
updateSnippet();
|
||||
|
||||
const prompt = ">>>>> ";
|
||||
const prompt = '>>>>> ';
|
||||
|
||||
const term = new Terminal();
|
||||
term.open(document.getElementById('terminal'));
|
||||
term.write(prompt);
|
||||
|
||||
function removeNonAscii(str) {
|
||||
if ((str===null) || (str===''))
|
||||
return false;
|
||||
else
|
||||
str = str.toString();
|
||||
if (str === null || str === '') return false;
|
||||
else str = str.toString();
|
||||
|
||||
return str.replace(/[^\x20-\x7E]/g, '');
|
||||
}
|
||||
|
||||
function printToConsole(data) {
|
||||
term.write(removeNonAscii(data) + "\r\n");
|
||||
term.write(removeNonAscii(data) + '\r\n');
|
||||
}
|
||||
|
||||
const terminalVM = rp.vmStore.init("term_vm");
|
||||
const terminalVM = rp.vmStore.init('term_vm');
|
||||
terminalVM.setStdout(printToConsole);
|
||||
|
||||
var input = "";
|
||||
term.on("data", (data) => {
|
||||
const code = data.charCodeAt(0);
|
||||
if (code == 13) { // CR
|
||||
if (input[input.length - 1] == ':') {
|
||||
input += data
|
||||
term.write("\r\n.....");
|
||||
} else {
|
||||
term.write("\r\n");
|
||||
try {
|
||||
terminalVM.exec(input);
|
||||
} catch (err) {
|
||||
if (err instanceof WebAssembly.RuntimeError) {
|
||||
err = window.__RUSTPYTHON_ERROR || err;
|
||||
var input = '';
|
||||
term.on('data', data => {
|
||||
const code = data.charCodeAt(0);
|
||||
if (code == 13) {
|
||||
// CR
|
||||
if (input[input.length - 1] == ':') {
|
||||
input += data;
|
||||
term.write('\r\n.....');
|
||||
} else {
|
||||
term.write('\r\n');
|
||||
try {
|
||||
terminalVM.exec(input);
|
||||
} catch (err) {
|
||||
if (err instanceof WebAssembly.RuntimeError) {
|
||||
err = window.__RUSTPYTHON_ERROR || err;
|
||||
}
|
||||
printToConsole(err);
|
||||
}
|
||||
printToConsole(err);
|
||||
term.write(prompt);
|
||||
input = '';
|
||||
}
|
||||
term.write(prompt);
|
||||
input = "";
|
||||
} else if (code == 127) {
|
||||
if (input.length > 0) {
|
||||
term.write('\b \b');
|
||||
input = input.slice(0, -1);
|
||||
}
|
||||
} else if (code < 32 || code == 127) {
|
||||
// Control
|
||||
return;
|
||||
} else {
|
||||
// Visible
|
||||
term.write(data);
|
||||
input += data;
|
||||
}
|
||||
} else if (code == 127) {
|
||||
if (input.length > 0) {
|
||||
term.write("\b \b");
|
||||
input = input.slice(0, -1);
|
||||
}
|
||||
} else if (code < 32 || code == 127) { // Control
|
||||
return;
|
||||
} else { // Visible
|
||||
term.write(data);
|
||||
input += data;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,7 +26,6 @@ features = [
|
||||
"console",
|
||||
"Document",
|
||||
"Element",
|
||||
"HtmlTextAreaElement",
|
||||
"Window",
|
||||
"Headers",
|
||||
"Request",
|
||||
|
||||
@@ -11,7 +11,7 @@ use rustpython_vm::{
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::{Rc, Weak};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
|
||||
pub trait HeldRcInner {}
|
||||
|
||||
@@ -271,13 +271,16 @@ impl WASMVirtualMachine {
|
||||
ref mut scope,
|
||||
..
|
||||
}| {
|
||||
fn error() -> JsValue {
|
||||
TypeError::new("Unknown stdout option, please pass a function or 'console'")
|
||||
.into()
|
||||
}
|
||||
let print_fn: Box<Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult> =
|
||||
if let Some(selector) = stdout.as_string() {
|
||||
Box::new(
|
||||
move |vm: &mut VirtualMachine, args: PyFuncArgs| -> PyResult {
|
||||
wasm_builtins::builtin_print_html(vm, args, &selector)
|
||||
},
|
||||
)
|
||||
if let Some(s) = stdout.as_string() {
|
||||
match s.as_str() {
|
||||
"console" => Box::new(wasm_builtins::builtin_print_console),
|
||||
_ => return Err(error()),
|
||||
}
|
||||
} else if stdout.is_function() {
|
||||
let func = js_sys::Function::from(stdout);
|
||||
Box::new(
|
||||
@@ -291,12 +294,12 @@ impl WASMVirtualMachine {
|
||||
},
|
||||
)
|
||||
} else if stdout.is_undefined() || stdout.is_null() {
|
||||
Box::new(wasm_builtins::builtin_print_console)
|
||||
fn noop(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
Box::new(noop)
|
||||
} else {
|
||||
return Err(TypeError::new(
|
||||
"stdout must be null, a function or a css selector",
|
||||
)
|
||||
.into());
|
||||
return Err(error());
|
||||
};
|
||||
scope.store_name(&vm, "print", vm.ctx.new_rustfunc(print_fn));
|
||||
Ok(())
|
||||
|
||||
@@ -4,43 +4,16 @@
|
||||
//! desktop.
|
||||
//! Implements functions listed here: https://docs.python.org/3/library/builtins.html.
|
||||
|
||||
use crate::convert;
|
||||
use js_sys::{self, Array};
|
||||
use rustpython_vm::obj::{objstr, objtype};
|
||||
use rustpython_vm::pyobject::{IdProtocol, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use web_sys::{self, console, HtmlTextAreaElement};
|
||||
use web_sys::{self, console};
|
||||
|
||||
pub(crate) fn window() -> web_sys::Window {
|
||||
web_sys::window().expect("Window to be available")
|
||||
}
|
||||
|
||||
// The HTML id of the textarea element that act as our STDOUT
|
||||
|
||||
pub fn print_to_html(text: &str, selector: &str) -> Result<(), JsValue> {
|
||||
let document = window().document().expect("Document to be available");
|
||||
let element = document
|
||||
.query_selector(selector)?
|
||||
.ok_or_else(|| js_sys::TypeError::new("Couldn't get element"))?;
|
||||
let textarea = element
|
||||
.dyn_ref::<HtmlTextAreaElement>()
|
||||
.ok_or_else(|| js_sys::TypeError::new("Element must be a textarea"))?;
|
||||
|
||||
let value = textarea.value();
|
||||
|
||||
let scroll_height = textarea.scroll_height();
|
||||
let scrolled_to_bottom = scroll_height - textarea.scroll_top() == textarea.client_height();
|
||||
|
||||
textarea.set_value(&format!("{}{}", value, text));
|
||||
|
||||
if scrolled_to_bottom {
|
||||
textarea.scroll_with_x_and_y(0.0, scroll_height.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn format_print_args(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<String, PyObjectRef> {
|
||||
// Handle 'sep' kwarg:
|
||||
let sep_arg = args
|
||||
@@ -93,12 +66,6 @@ pub fn format_print_args(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<St
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn builtin_print_html(vm: &mut VirtualMachine, args: PyFuncArgs, selector: &str) -> PyResult {
|
||||
let output = format_print_args(vm, args)?;
|
||||
print_to_html(&output, selector).map_err(|err| convert::js_to_py(vm, err))?;
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
|
||||
pub fn builtin_print_console(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let arr = Array::new();
|
||||
for arg in args.args {
|
||||
|
||||
Reference in New Issue
Block a user