Skip to content
Merged
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
81 changes: 45 additions & 36 deletions wasm/demo/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`;
Expand Down Expand Up @@ -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 == 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 < 32 || code == 127) { // Control
return;
} else { // Visible
term.write(data);
input += data;
}
});
1 change: 0 additions & 1 deletion wasm/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ features = [
"console",
"Document",
"Element",
"HtmlTextAreaElement",
"Window",
"Headers",
"Request",
Expand Down
27 changes: 15 additions & 12 deletions wasm/lib/src/vm_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down Expand Up @@ -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(
Expand All @@ -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(())
Expand Down
35 changes: 1 addition & 34 deletions wasm/lib/src/wasm_builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down