Refactor command dispatch and state handling.
This commit is contained in:
		
							parent
							
								
									1b14973b1d
								
							
						
					
					
						commit
						c0131aca62
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1415,6 +1415,7 @@ dependencies = [
 | 
			
		||||
name = "worldwideportal"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "console_error_panic_hook",
 | 
			
		||||
 "im",
 | 
			
		||||
 "itertools 0.13.0",
 | 
			
		||||
 | 
			
		||||
@ -19,3 +19,4 @@ minicrossterm = { git = "https://git.blastmud.org/blasthavers/minicrossterm.git"
 | 
			
		||||
thiserror = "1.0.63"
 | 
			
		||||
console_error_panic_hook = "0.1.7"
 | 
			
		||||
ouroboros = "0.18.4"
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
 | 
			
		||||
@ -1,28 +1,25 @@
 | 
			
		||||
use itertools::join;
 | 
			
		||||
use std::{cell::RefCell, rc::Rc};
 | 
			
		||||
use yew::Callback;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    echo_to_term_frame, lua_state::LuaState, parsing::parse_commands, RegisteredTermFrameLens,
 | 
			
		||||
    TermFrame,
 | 
			
		||||
    echo_to_term_frame, lua_state::LuaState, parsing::parse_commands, GlobalCell, TermFrame,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fn reentrant_command_handler(
 | 
			
		||||
    lua_state: &mut LuaState,
 | 
			
		||||
    frames: &RegisteredTermFrameLens,
 | 
			
		||||
    globals: &GlobalCell,
 | 
			
		||||
    term_frame: &TermFrame,
 | 
			
		||||
    command_in: &str,
 | 
			
		||||
) {
 | 
			
		||||
    web_sys::console::log_1(&"Inside command handler".into());
 | 
			
		||||
    echo_to_term_frame(frames, term_frame, "Hello World!\n");
 | 
			
		||||
    echo_to_term_frame(globals, term_frame, "Hello World!\n").unwrap_or(());
 | 
			
		||||
    for command in parse_commands(command_in).commands {
 | 
			
		||||
        match command.split_out_command() {
 | 
			
		||||
            None => (),
 | 
			
		||||
            Some((cmd, rest)) => {
 | 
			
		||||
                if cmd == "##" {
 | 
			
		||||
                    match lua_state.execute(&join(rest.arguments.iter(), " ")) {
 | 
			
		||||
                        Ok(msg) => echo_to_term_frame(frames, term_frame, &msg).unwrap_or(()),
 | 
			
		||||
                        Err(msg) => echo_to_term_frame(frames, term_frame, &msg).unwrap_or(()),
 | 
			
		||||
                        Ok(msg) => echo_to_term_frame(globals, term_frame, &msg).unwrap_or(()),
 | 
			
		||||
                        Err(msg) => echo_to_term_frame(globals, term_frame, &msg).unwrap_or(()),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -30,28 +27,16 @@ fn reentrant_command_handler(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn command_handler(
 | 
			
		||||
    lua_state: &RefCell<LuaState>,
 | 
			
		||||
    frames: &RegisteredTermFrameLens,
 | 
			
		||||
    term_frame: &TermFrame,
 | 
			
		||||
    command_in: String,
 | 
			
		||||
) {
 | 
			
		||||
    match lua_state.try_borrow_mut() {
 | 
			
		||||
pub fn command_handler(globals: &GlobalCell, term_frame: &TermFrame, command_in: &str) {
 | 
			
		||||
    match globals.lua_engine.try_borrow_mut() {
 | 
			
		||||
        Err(_) => echo_to_term_frame(
 | 
			
		||||
            frames,
 | 
			
		||||
            globals,
 | 
			
		||||
            term_frame,
 | 
			
		||||
            "Attempt to re-enter command handler during processing.\n",
 | 
			
		||||
        )
 | 
			
		||||
        .unwrap_or(()), // Ignore error handling error.
 | 
			
		||||
        Ok(mut lua_state_m) => {
 | 
			
		||||
            reentrant_command_handler(&mut lua_state_m, frames, term_frame, &command_in)
 | 
			
		||||
            reentrant_command_handler(&mut lua_state_m, globals, term_frame, command_in)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn make_command_handler_callback(
 | 
			
		||||
    lua_state: Rc<RefCell<LuaState>>,
 | 
			
		||||
    frames: RegisteredTermFrameLens,
 | 
			
		||||
) -> Callback<(TermFrame, String), ()> {
 | 
			
		||||
    Callback::from(move |(term, cmd)| command_handler(&lua_state, &frames, &term, cmd))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
use anyhow::Error;
 | 
			
		||||
use piccolo::{Callback, Closure, Context, Executor, IntoValue, Lua, StashedExecutor, Table};
 | 
			
		||||
 | 
			
		||||
use crate::{echo_to_term_frame, RegisteredTermFrameLens, TermFrame};
 | 
			
		||||
use crate::{echo_to_term_frame, GlobalCell, TermFrame};
 | 
			
		||||
use std::str;
 | 
			
		||||
 | 
			
		||||
pub struct LuaState {
 | 
			
		||||
@ -9,22 +10,10 @@ pub struct LuaState {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LuaState {
 | 
			
		||||
    pub fn setup(frames: RegisteredTermFrameLens) -> Result<LuaState, String> {
 | 
			
		||||
    pub fn setup() -> Result<LuaState, String> {
 | 
			
		||||
        let mut interp = Lua::core();
 | 
			
		||||
        let exec: StashedExecutor = interp.enter(|ctx| {
 | 
			
		||||
            let cmd_table = Table::new(&ctx);
 | 
			
		||||
            cmd_table
 | 
			
		||||
                .set(
 | 
			
		||||
                    ctx,
 | 
			
		||||
                    ctx.intern_static(b"echo_frame"),
 | 
			
		||||
                    echo_frame(ctx, frames),
 | 
			
		||||
                )
 | 
			
		||||
                .map_err(|_| "Can't add command")?;
 | 
			
		||||
            ctx.set_global(ctx.intern_static(b"commands").into_value(ctx), cmd_table)
 | 
			
		||||
                .map(|_| ())
 | 
			
		||||
                .map_err(|_| "Can't set commands key".to_owned())?;
 | 
			
		||||
            Ok::<StashedExecutor, String>(ctx.stash(Executor::new(ctx)))
 | 
			
		||||
        })?;
 | 
			
		||||
        let exec: StashedExecutor =
 | 
			
		||||
            interp.enter(|ctx| Ok::<StashedExecutor, String>(ctx.stash(Executor::new(ctx))))?;
 | 
			
		||||
 | 
			
		||||
        Ok(LuaState { interp, exec })
 | 
			
		||||
    }
 | 
			
		||||
@ -42,13 +31,37 @@ impl LuaState {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn echo_frame(ctx: Context, frames: RegisteredTermFrameLens) -> Callback {
 | 
			
		||||
pub fn install_lua_globals(global: &GlobalCell) -> Result<(), String> {
 | 
			
		||||
    global
 | 
			
		||||
        .lua_engine
 | 
			
		||||
        .borrow_mut()
 | 
			
		||||
        .interp
 | 
			
		||||
        .try_enter(|ctx| {
 | 
			
		||||
            let cmd_table = Table::new(&ctx);
 | 
			
		||||
            cmd_table
 | 
			
		||||
                .set(
 | 
			
		||||
                    ctx,
 | 
			
		||||
                    ctx.intern_static(b"echo_frame"),
 | 
			
		||||
                    echo_frame(ctx, global.clone()),
 | 
			
		||||
                )
 | 
			
		||||
                .map_err(|_| Error::msg("Can't add command"))?;
 | 
			
		||||
            ctx.set_global(ctx.intern_static(b"commands").into_value(ctx), cmd_table)
 | 
			
		||||
                .map(|_| ())
 | 
			
		||||
                .map_err(|_| Error::msg("Can't set commands key"))?;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
        .map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn echo_frame(ctx: Context, global: GlobalCell) -> Callback {
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let frame_no: u64 = stack.consume(ctx)?;
 | 
			
		||||
        let message: piccolo::String = stack.consume(ctx)?;
 | 
			
		||||
        let message_str = str::from_utf8(message.as_bytes())
 | 
			
		||||
            .map_err(|_| "Expected message to echo to be UTF-8.".into_value(ctx))?;
 | 
			
		||||
        echo_to_term_frame(&frames, &TermFrame(frame_no), message_str)
 | 
			
		||||
        echo_to_term_frame(&global, &TermFrame(frame_no), message_str)
 | 
			
		||||
            .map_err(|m| m.into_value(ctx))?;
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/main.rs
									
									
									
									
									
								
							@ -8,15 +8,16 @@ pub mod lineengine;
 | 
			
		||||
pub mod lua_state;
 | 
			
		||||
pub mod parsing;
 | 
			
		||||
pub mod term_view;
 | 
			
		||||
use crate::command_handler::*;
 | 
			
		||||
use crate::lua_state::LuaState;
 | 
			
		||||
use crate::lua_state::{install_lua_globals, LuaState};
 | 
			
		||||
use crate::term_view::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Properties)]
 | 
			
		||||
struct GlobalState {
 | 
			
		||||
    frame_registry: RegisteredTermFrames,
 | 
			
		||||
    lua_engine: LuaState,
 | 
			
		||||
pub struct GlobalState {
 | 
			
		||||
    // No strong references allowed between each of these groups of state.
 | 
			
		||||
    frame_registry: RefCell<RegisteredTermFrames>,
 | 
			
		||||
    lua_engine: RefCell<LuaState>,
 | 
			
		||||
}
 | 
			
		||||
type GlobalCell = Rc<GlobalState>;
 | 
			
		||||
 | 
			
		||||
// Used only for yew. Always equal since we don't want it to
 | 
			
		||||
// actually look into GlobalState, changes there should never
 | 
			
		||||
@ -29,15 +30,16 @@ impl PartialEq for GlobalState {
 | 
			
		||||
 | 
			
		||||
#[function_component(App)]
 | 
			
		||||
fn app() -> Html {
 | 
			
		||||
    let global = use_mut_ref(|| Global {
 | 
			
		||||
    let global = use_memo((), |_| GlobalState {
 | 
			
		||||
        frame_registry: RegisteredTermFrames::new().into(),
 | 
			
		||||
        lua_engine: LuaState::setup(frames.clone()).expect("Can create interpreter"),
 | 
			
		||||
        lua_engine: LuaState::setup().expect("Can create interpreter").into(),
 | 
			
		||||
    });
 | 
			
		||||
    install_lua_globals(&global).expect("Couldn't install Lua globals");
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <div class="vpane toplevel">
 | 
			
		||||
            <TermView terminal={TermFrame(0)} frames={frames.clone()} handler={command_handler.clone()}/>
 | 
			
		||||
            <TermView terminal={TermFrame(1)} frames={frames.clone()} handler={command_handler.clone()}/>
 | 
			
		||||
            <TermView terminal={TermFrame(0)} global={global.clone()}/>
 | 
			
		||||
            <TermView terminal={TermFrame(1)} global={global.clone()}/>
 | 
			
		||||
        </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										220
									
								
								src/term_view.rs
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								src/term_view.rs
									
									
									
									
									
								
							@ -1,14 +1,14 @@
 | 
			
		||||
use std::{
 | 
			
		||||
    cell::RefCell,
 | 
			
		||||
    rc::{Rc, Weak},
 | 
			
		||||
};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use im::hashmap::*;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
use web_sys::{Element, Node};
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::lineengine::line::{Readline, ReadlineEvent};
 | 
			
		||||
use crate::{
 | 
			
		||||
    command_handler::command_handler,
 | 
			
		||||
    lineengine::line::{Readline, ReadlineEvent},
 | 
			
		||||
    GlobalCell,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
extern "C" {
 | 
			
		||||
@ -73,8 +73,8 @@ pub struct TermFrameData {
 | 
			
		||||
    pub term: Terminal,
 | 
			
		||||
    pub fit: FitAddon,
 | 
			
		||||
    pub node: Node,
 | 
			
		||||
    pub readline: RefCell<Readline>,
 | 
			
		||||
    pub retained_closures: RefCell<Option<(Closure<dyn FnMut(String)>, Closure<dyn FnMut(Dims)>)>>,
 | 
			
		||||
    pub readline: Readline,
 | 
			
		||||
    pub retained_closures: Option<(Closure<dyn FnMut(String)>, Closure<dyn FnMut(Dims)>)>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialEq for TermFrameData {
 | 
			
		||||
@ -84,109 +84,114 @@ impl PartialEq for TermFrameData {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type RegisteredTermFrames = HashMap<TermFrame, Rc<TermFrameData>>;
 | 
			
		||||
#[derive(Properties, PartialEq, Clone)]
 | 
			
		||||
pub struct RegisteredTermFrameLens {
 | 
			
		||||
    pub get: Callback<(), Rc<RegisteredTermFrames>>,
 | 
			
		||||
    pub set: Callback<Rc<RegisteredTermFrames>, ()>,
 | 
			
		||||
}
 | 
			
		||||
pub type RegisteredTermFrames = HashMap<TermFrame, TermFrameData>;
 | 
			
		||||
 | 
			
		||||
fn get_or_make_term_frame(
 | 
			
		||||
fn get_or_make_term_frame<'a>(
 | 
			
		||||
    frame: &TermFrame,
 | 
			
		||||
    frames: &RegisteredTermFrameLens,
 | 
			
		||||
    handler: &Callback<(TermFrame, String), ()>,
 | 
			
		||||
) -> Rc<TermFrameData> {
 | 
			
		||||
    if let Some(tfd) = frames.get.emit(()).get(frame) {
 | 
			
		||||
        return tfd.clone();
 | 
			
		||||
    }
 | 
			
		||||
    frames: &'a mut RegisteredTermFrames,
 | 
			
		||||
    // Only used for callbacks, expected frames already borrowed mut!
 | 
			
		||||
    globals: &GlobalCell,
 | 
			
		||||
) -> &'a TermFrameData {
 | 
			
		||||
    frames.entry(frame.clone()).or_insert_with(|| {
 | 
			
		||||
        let term = Terminal::new();
 | 
			
		||||
        let fit = FitAddon::new();
 | 
			
		||||
        let element = web_sys::window()
 | 
			
		||||
            .and_then(|w| w.document())
 | 
			
		||||
            .and_then(|d| d.create_element("div").ok())
 | 
			
		||||
            .expect("Can create element for term");
 | 
			
		||||
        element.set_class_name("hterminal");
 | 
			
		||||
        term.open(&element);
 | 
			
		||||
        term.loadAddon(&fit);
 | 
			
		||||
        fit.fit();
 | 
			
		||||
        for i in 0..100 {
 | 
			
		||||
            term.write(&format!("{} Hello world\r\n", i));
 | 
			
		||||
        }
 | 
			
		||||
        let term_for_readline: Terminal = Terminal { obj: term.clone() };
 | 
			
		||||
        let initial_size = (term.cols(), term.rows());
 | 
			
		||||
        let mut new_data: TermFrameData = TermFrameData {
 | 
			
		||||
            id: frame.clone(),
 | 
			
		||||
            term: Terminal { obj: term.clone() },
 | 
			
		||||
            fit,
 | 
			
		||||
            node: element.into(),
 | 
			
		||||
            readline: Readline::new(
 | 
			
		||||
                "".to_owned(),
 | 
			
		||||
                Box::new(move |dat| {
 | 
			
		||||
                    term_for_readline.write(
 | 
			
		||||
                        std::str::from_utf8(dat).expect("readline tried to emit invalid UTF-8"),
 | 
			
		||||
                    )
 | 
			
		||||
                }),
 | 
			
		||||
                initial_size,
 | 
			
		||||
            )
 | 
			
		||||
            .into(),
 | 
			
		||||
            retained_closures: None,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    let mut new_frames: RegisteredTermFrames = (*frames.get.emit(())).clone();
 | 
			
		||||
    let term = Terminal::new();
 | 
			
		||||
    let fit = FitAddon::new();
 | 
			
		||||
    let element = web_sys::window()
 | 
			
		||||
        .and_then(|w| w.document())
 | 
			
		||||
        .and_then(|d| d.create_element("div").ok())
 | 
			
		||||
        .expect("Can create element for term");
 | 
			
		||||
    element.set_class_name("hterminal");
 | 
			
		||||
    term.open(&element);
 | 
			
		||||
    term.loadAddon(&fit);
 | 
			
		||||
    fit.fit();
 | 
			
		||||
    for i in 0..100 {
 | 
			
		||||
        term.write(&format!("{} Hello world\r\n", i));
 | 
			
		||||
    }
 | 
			
		||||
    let term_for_readline: Terminal = Terminal { obj: term.clone() };
 | 
			
		||||
    let initial_size = (term.cols(), term.rows());
 | 
			
		||||
    let new_data: Rc<TermFrameData> = TermFrameData {
 | 
			
		||||
        id: frame.clone(),
 | 
			
		||||
        term: Terminal { obj: term.clone() },
 | 
			
		||||
        fit,
 | 
			
		||||
        node: element.into(),
 | 
			
		||||
        readline: Readline::new(
 | 
			
		||||
            "".to_owned(),
 | 
			
		||||
            Box::new(move |dat| {
 | 
			
		||||
                term_for_readline
 | 
			
		||||
                    .write(std::str::from_utf8(dat).expect("readline tried to emit invalid UTF-8"))
 | 
			
		||||
            }),
 | 
			
		||||
            initial_size,
 | 
			
		||||
        )
 | 
			
		||||
        .into(),
 | 
			
		||||
        retained_closures: RefCell::new(None),
 | 
			
		||||
    }
 | 
			
		||||
    .into();
 | 
			
		||||
        let frame_for_resize: TermFrame = frame.clone();
 | 
			
		||||
        let globals_for_resize: GlobalCell = globals.clone();
 | 
			
		||||
        let resize_closure = Closure::new(move |dims: Dims| {
 | 
			
		||||
            globals_for_resize
 | 
			
		||||
                .frame_registry
 | 
			
		||||
                .try_borrow_mut()
 | 
			
		||||
                .ok()
 | 
			
		||||
                .and_then(|mut frame_reg| {
 | 
			
		||||
                    frame_reg.get_mut(&frame_for_resize).and_then(|frame| {
 | 
			
		||||
                        frame
 | 
			
		||||
                            .readline
 | 
			
		||||
                            .handle_resize((dims.cols(), dims.rows()))
 | 
			
		||||
                            .ok()
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
                .unwrap_or(())
 | 
			
		||||
        });
 | 
			
		||||
        term.onResize(&resize_closure);
 | 
			
		||||
 | 
			
		||||
    let data_for_resize: Weak<TermFrameData> = Rc::downgrade(&new_data);
 | 
			
		||||
    let resize_closure = Closure::new(move |dims: Dims| match Weak::upgrade(&data_for_resize) {
 | 
			
		||||
        None => {}
 | 
			
		||||
        Some(r) => match r.readline.try_borrow_mut() {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            Ok(mut v) => v.handle_resize((dims.cols(), dims.rows())).unwrap_or(()),
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
    term.onResize(&resize_closure);
 | 
			
		||||
 | 
			
		||||
    let cloned_handler = (*handler).clone();
 | 
			
		||||
    let emit_frame = frame.clone();
 | 
			
		||||
    let data_for_on_data: Weak<TermFrameData> = Rc::downgrade(&new_data);
 | 
			
		||||
 | 
			
		||||
    let data_closure = Closure::new(move |d: String| match Weak::upgrade(&data_for_on_data) {
 | 
			
		||||
        None => {}
 | 
			
		||||
        Some(r) => match r.readline.try_borrow_mut() {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            Ok(mut v) => {
 | 
			
		||||
                for ev in v.readline(d.as_bytes()).expect("Readline failed") {
 | 
			
		||||
                    match ev {
 | 
			
		||||
                        ReadlineEvent::Line(l) => cloned_handler.emit((emit_frame.clone(), l)),
 | 
			
		||||
                        _ => {}
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        let frame_for_ondata: TermFrame = frame.clone();
 | 
			
		||||
        let globals_for_ondata: GlobalCell = globals.clone();
 | 
			
		||||
        let data_closure = Closure::new(move |d: String| {
 | 
			
		||||
            let new_lines: Vec<String> = match globals_for_ondata
 | 
			
		||||
                .frame_registry
 | 
			
		||||
                .try_borrow_mut()
 | 
			
		||||
                .expect("Unexpected failure to borrow frame registry in onData")
 | 
			
		||||
                .get_mut(&frame_for_ondata)
 | 
			
		||||
            {
 | 
			
		||||
                None => vec![],
 | 
			
		||||
                Some(frame) => frame
 | 
			
		||||
                    .readline
 | 
			
		||||
                    .readline(d.as_bytes())
 | 
			
		||||
                    .expect("Readline failed")
 | 
			
		||||
                    .into_iter()
 | 
			
		||||
                    .filter_map(|ev| match ev {
 | 
			
		||||
                        ReadlineEvent::Line(l) => Some(l),
 | 
			
		||||
                        _ => None,
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            };
 | 
			
		||||
            // We deliberately stop borrowing anything from RefCells here since command_handler has
 | 
			
		||||
            // lots of its own borrows, and we don't want them to conflict.
 | 
			
		||||
            for cmd in &new_lines {
 | 
			
		||||
                command_handler(&globals_for_ondata, &frame_for_ondata, cmd);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    term.onData(&data_closure);
 | 
			
		||||
    new_data
 | 
			
		||||
        .retained_closures
 | 
			
		||||
        .replace(Some((data_closure, resize_closure)));
 | 
			
		||||
        term.onData(&data_closure);
 | 
			
		||||
        new_data
 | 
			
		||||
            .retained_closures
 | 
			
		||||
            .replace((data_closure, resize_closure));
 | 
			
		||||
 | 
			
		||||
    new_frames.insert(frame.clone(), new_data.clone());
 | 
			
		||||
    web_sys::console::log_2(
 | 
			
		||||
        &"Setting frames to have length: ".into(),
 | 
			
		||||
        &new_frames.iter().count().into(),
 | 
			
		||||
    );
 | 
			
		||||
    frames.set.emit(new_frames.into());
 | 
			
		||||
    new_data
 | 
			
		||||
        new_data
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct TermViewProps {
 | 
			
		||||
    pub terminal: TermFrame,
 | 
			
		||||
    pub frames: RegisteredTermFrameLens,
 | 
			
		||||
    pub handler: Callback<(TermFrame, String), ()>,
 | 
			
		||||
    pub global: GlobalCell,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component(TermView)]
 | 
			
		||||
pub fn term_view(props: &TermViewProps) -> Html {
 | 
			
		||||
    let term = get_or_make_term_frame(&props.terminal, &props.frames, &props.handler);
 | 
			
		||||
    let mut frame_reg = props.global.frame_registry.borrow_mut();
 | 
			
		||||
    let term = get_or_make_term_frame(&props.terminal, &mut frame_reg, &props.global);
 | 
			
		||||
    term.fit.fit();
 | 
			
		||||
    html! {
 | 
			
		||||
        {Html::VRef(term.node.clone())}
 | 
			
		||||
@ -194,19 +199,22 @@ pub fn term_view(props: &TermViewProps) -> Html {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn echo_to_term_frame(
 | 
			
		||||
    frames: &RegisteredTermFrameLens,
 | 
			
		||||
    global: &GlobalCell,
 | 
			
		||||
    frame_id: &TermFrame,
 | 
			
		||||
    message: &str,
 | 
			
		||||
) -> Result<(), &'static str> {
 | 
			
		||||
    let frame_val = frames.get.emit(());
 | 
			
		||||
    let frame: &TermFrameData = frame_val.get(frame_id).ok_or_else(|| {
 | 
			
		||||
        web_sys::console::log_3(
 | 
			
		||||
            &"Attempt to echo to frame that doesn't exist.".into(),
 | 
			
		||||
            &frame_id.0.into(),
 | 
			
		||||
            &frame_val.iter().count().into(),
 | 
			
		||||
        );
 | 
			
		||||
        "Attempt to echo to frame that doesn't exist."
 | 
			
		||||
    })?;
 | 
			
		||||
    frame.term.write(message);
 | 
			
		||||
    global
 | 
			
		||||
        .frame_registry
 | 
			
		||||
        .borrow()
 | 
			
		||||
        .get(frame_id)
 | 
			
		||||
        .ok_or_else(|| {
 | 
			
		||||
            web_sys::console::log_2(
 | 
			
		||||
                &"Attempt to echo to frame that doesn't exist.".into(),
 | 
			
		||||
                &frame_id.0.into(),
 | 
			
		||||
            );
 | 
			
		||||
            "Attempt to echo to frame that doesn't exist."
 | 
			
		||||
        })?
 | 
			
		||||
        .term
 | 
			
		||||
        .write(message);
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user