Set up frameroutes to route MUD messages to termframes
This commit is contained in:
		
							parent
							
								
									1015bcb4ad
								
							
						
					
					
						commit
						ff0411b040
					
				
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -747,7 +747,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "minicrossterm"
 | 
			
		||||
version = "0.28.1"
 | 
			
		||||
source = "git+https://git.blastmud.org/blasthavers/minicrossterm.git?rev=494f89daef41162fbd89d5266e261018ed5ff6dc#494f89daef41162fbd89d5266e261018ed5ff6dc"
 | 
			
		||||
source = "git+https://git.blastmud.org/blasthavers/minicrossterm.git?rev=0c8c6d4f0cf445adf7bb957811081a1b710bd933#0c8c6d4f0cf445adf7bb957811081a1b710bd933"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ unicode-width = "0.1.13"
 | 
			
		||||
wasm-bindgen = "0.2.92"
 | 
			
		||||
web-sys = { version = "0.3.69", features = ["ResizeObserver", "DomRect", "CssStyleDeclaration"] }
 | 
			
		||||
yew = { version = "0.21.0", features = ["csr"] }
 | 
			
		||||
minicrossterm = { git = "https://git.blastmud.org/blasthavers/minicrossterm.git", rev = "494f89daef41162fbd89d5266e261018ed5ff6dc" }
 | 
			
		||||
minicrossterm = { git = "https://git.blastmud.org/blasthavers/minicrossterm.git", rev = "0c8c6d4f0cf445adf7bb957811081a1b710bd933" }
 | 
			
		||||
thiserror = "1.0.63"
 | 
			
		||||
console_error_panic_hook = "0.1.7"
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
use self::{frames::*, muds::*};
 | 
			
		||||
use self::{frameroutes::*, frames::*, muds::*};
 | 
			
		||||
use anyhow::Error;
 | 
			
		||||
use piccolo::{
 | 
			
		||||
    Callback, Closure, Context, Executor, ExternError, FromValue, Function, Lua, StashedExecutor,
 | 
			
		||||
    async_callback::Locals, meta_ops::MetaResult, Callback, Closure, Context, Executor,
 | 
			
		||||
    ExternError, FromValue, Function, Lua, MetaMethod, Stack, StashedExecutor, StashedFunction,
 | 
			
		||||
    Table, Value, Variadic,
 | 
			
		||||
};
 | 
			
		||||
use yew::UseStateSetter;
 | 
			
		||||
@ -14,7 +15,8 @@ pub struct LuaState {
 | 
			
		||||
    pub exec: StashedExecutor,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod frames;
 | 
			
		||||
mod frameroutes;
 | 
			
		||||
pub mod frames;
 | 
			
		||||
pub mod muds;
 | 
			
		||||
 | 
			
		||||
impl LuaState {
 | 
			
		||||
@ -94,78 +96,119 @@ pub fn install_lua_globals(
 | 
			
		||||
    global_memo: &GlobalMemoCell,
 | 
			
		||||
    global_layout: UseStateSetter<GlobalLayoutCell>,
 | 
			
		||||
) -> Result<(), String> {
 | 
			
		||||
    global_memo.lua_engine.borrow_mut().interp.try_enter(|ctx| {
 | 
			
		||||
        let cmd_table = Table::new(&ctx);
 | 
			
		||||
        macro_rules! register_command {
 | 
			
		||||
            ($sym: ident) => {
 | 
			
		||||
                cmd_table
 | 
			
		||||
                    .set(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                        $sym(ctx, &global_memo, &global_layout),
 | 
			
		||||
                    )
 | 
			
		||||
                    .map_err(|_| Error::msg("Can't add command"))?;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    global_memo
 | 
			
		||||
        .lua_engine
 | 
			
		||||
        .borrow_mut()
 | 
			
		||||
        .interp
 | 
			
		||||
        .try_enter(|ctx| {
 | 
			
		||||
            let cmd_table = Table::new(&ctx);
 | 
			
		||||
            macro_rules! register_command {
 | 
			
		||||
                ($sym: ident) => {
 | 
			
		||||
                    cmd_table
 | 
			
		||||
                        .set(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                            $sym(ctx, &global_memo, &global_layout),
 | 
			
		||||
                        )
 | 
			
		||||
                        .map_err(|_| Error::msg("Can't add command"))?;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        register_command!(echo);
 | 
			
		||||
        register_command!(echo_frame);
 | 
			
		||||
        register_command!(echo_frame_raw);
 | 
			
		||||
        register_command!(connect_mud);
 | 
			
		||||
        register_command!(delete_mud);
 | 
			
		||||
        register_command!(close_mud);
 | 
			
		||||
        register_command!(sendmud_raw);
 | 
			
		||||
        register_command!(hsplit);
 | 
			
		||||
        register_command!(panel_merge);
 | 
			
		||||
        register_command!(vsplit);
 | 
			
		||||
        ctx.set_global("commands", cmd_table);
 | 
			
		||||
        let info_table = Table::new(&ctx);
 | 
			
		||||
        ctx.set_global("info", info_table);
 | 
			
		||||
        let muds_table = Table::new(&ctx);
 | 
			
		||||
        ctx.set_global("muds", muds_table);
 | 
			
		||||
            register_command!(echo);
 | 
			
		||||
            register_command!(echo_frame);
 | 
			
		||||
            register_command!(echo_frame_raw);
 | 
			
		||||
            register_command!(connect_mud);
 | 
			
		||||
            register_command!(delete_mud);
 | 
			
		||||
            register_command!(close_mud);
 | 
			
		||||
            register_command!(sendmud_raw);
 | 
			
		||||
            register_command!(hsplit);
 | 
			
		||||
            register_command!(panel_merge);
 | 
			
		||||
            register_command!(vsplit);
 | 
			
		||||
            ctx.set_global("commands", cmd_table);
 | 
			
		||||
            let info_table = Table::new(&ctx);
 | 
			
		||||
            ctx.set_global("info", info_table);
 | 
			
		||||
            let muds_table = Table::new(&ctx);
 | 
			
		||||
            ctx.set_global("muds", muds_table);
 | 
			
		||||
 | 
			
		||||
        let handlers_table = Table::new(&ctx);
 | 
			
		||||
        ctx.set_global("handlers", handlers_table);
 | 
			
		||||
        macro_rules! register_handler {
 | 
			
		||||
            ($sym: ident) => {
 | 
			
		||||
                handlers_table
 | 
			
		||||
                    .set(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                        $sym(ctx, &global_memo),
 | 
			
		||||
                    )
 | 
			
		||||
                    .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        register_handler!(mudoutput);
 | 
			
		||||
        register_handler!(mudoutput_line);
 | 
			
		||||
        register_handler!(mudoutput_prompt);
 | 
			
		||||
        register_handler!(mudoutput_will);
 | 
			
		||||
        register_handler!(mudoutput_wont);
 | 
			
		||||
        register_handler!(mudoutput_do);
 | 
			
		||||
        register_handler!(mudoutput_dont);
 | 
			
		||||
        register_handler!(mudoutput_subnegotiation);
 | 
			
		||||
            let handlers_table = Table::new(&ctx);
 | 
			
		||||
            ctx.set_global("handlers", handlers_table);
 | 
			
		||||
            macro_rules! register_handler {
 | 
			
		||||
                ($sym: ident) => {
 | 
			
		||||
                    handlers_table
 | 
			
		||||
                        .set(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                            $sym(ctx, &global_memo),
 | 
			
		||||
                        )
 | 
			
		||||
                        .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            register_handler!(mudoutput);
 | 
			
		||||
 | 
			
		||||
        macro_rules! register_nop_handler {
 | 
			
		||||
            ($sym: ident) => {
 | 
			
		||||
                handlers_table
 | 
			
		||||
                    .set(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                        lua_nop(ctx),
 | 
			
		||||
                    )
 | 
			
		||||
                    .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
            let classes_table = Table::new(&ctx);
 | 
			
		||||
            ctx.set_global("classes", classes_table);
 | 
			
		||||
 | 
			
		||||
        register_nop_handler!(mudoutput_break);
 | 
			
		||||
        register_nop_handler!(mudoutput_sync);
 | 
			
		||||
        register_nop_handler!(mudoutput_interrupt);
 | 
			
		||||
        register_nop_handler!(mudoutput_abort_output);
 | 
			
		||||
        register_nop_handler!(mudoutput_areyouthere);
 | 
			
		||||
            let mud_class_table = Table::new(&ctx);
 | 
			
		||||
            classes_table.set(ctx, "mud", mud_class_table)?;
 | 
			
		||||
            mud_class_table.set(ctx, MetaMethod::Index, mud_class_table)?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    });
 | 
			
		||||
            macro_rules! register_class_function {
 | 
			
		||||
                ($class_table: ident, $sym: ident) => {
 | 
			
		||||
                    $class_table
 | 
			
		||||
                        .set(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                            $sym(ctx, &global_memo),
 | 
			
		||||
                        )
 | 
			
		||||
                        .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
                };
 | 
			
		||||
                ($class_table: ident, $name: literal, $sym: ident) => {
 | 
			
		||||
                    $class_table
 | 
			
		||||
                        .set(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            ctx.intern_static($name.as_bytes()),
 | 
			
		||||
                            $sym(ctx, &global_memo),
 | 
			
		||||
                        )
 | 
			
		||||
                        .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_line);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_prompt);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_will);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_wont);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_do);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_dont);
 | 
			
		||||
            register_class_function!(mud_class_table, mudoutput_subnegotiation);
 | 
			
		||||
            register_class_function!(mud_class_table, "new", new_mud);
 | 
			
		||||
 | 
			
		||||
            macro_rules! register_class_nop {
 | 
			
		||||
                ($class_table: ident, $sym: ident) => {
 | 
			
		||||
                    $class_table
 | 
			
		||||
                        .set(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            ctx.intern_static(stringify!($sym).as_bytes()),
 | 
			
		||||
                            lua_nop(ctx),
 | 
			
		||||
                        )
 | 
			
		||||
                        .map_err(|_| Error::msg("Can't add handler"))?;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            register_class_nop!(mud_class_table, mudoutput_break);
 | 
			
		||||
            register_class_nop!(mud_class_table, mudoutput_sync);
 | 
			
		||||
            register_class_nop!(mud_class_table, mudoutput_interrupt);
 | 
			
		||||
            register_class_nop!(mud_class_table, mudoutput_abort_output);
 | 
			
		||||
            register_class_nop!(mud_class_table, mudoutput_areyouthere);
 | 
			
		||||
 | 
			
		||||
            let frameroute_class_table = Table::new(&ctx);
 | 
			
		||||
            classes_table.set(ctx, "frameroute", frameroute_class_table)?;
 | 
			
		||||
            frameroute_class_table.set(ctx, MetaMethod::Index, frameroute_class_table)?;
 | 
			
		||||
            register_class_function!(frameroute_class_table, "new", new_frameroute);
 | 
			
		||||
            register_class_function!(frameroute_class_table, "route", frameroute_route);
 | 
			
		||||
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
        .map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
@ -175,3 +218,22 @@ pub fn lua_nop(ctx: Context<'_>) -> Callback<'_> {
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Borrowed from piccolo source.
 | 
			
		||||
pub fn prep_metaop_call<'gc, const N: usize>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    mut stack: Stack<'gc, '_>,
 | 
			
		||||
    locals: Locals<'gc, '_>,
 | 
			
		||||
    res: MetaResult<'gc, N>,
 | 
			
		||||
) -> Option<StashedFunction> {
 | 
			
		||||
    match res {
 | 
			
		||||
        MetaResult::Value(v) => {
 | 
			
		||||
            stack.push_back(v);
 | 
			
		||||
            None
 | 
			
		||||
        }
 | 
			
		||||
        MetaResult::Call(call) => {
 | 
			
		||||
            stack.extend(call.args);
 | 
			
		||||
            Some(locals.stash(&ctx, call.function))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/lua_engine/frameroutes.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/lua_engine/frameroutes.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
use piccolo::{Callback, CallbackReturn, Context, FromValue, Table};
 | 
			
		||||
 | 
			
		||||
use crate::{echo_to_term_frame, id_intern::intern_id, GlobalMemoCell, TermFrame};
 | 
			
		||||
 | 
			
		||||
use super::try_unwrap_frame;
 | 
			
		||||
 | 
			
		||||
pub(super) fn new_frameroute<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    _global_memo: &GlobalMemoCell,
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let frameroute: Table = Table::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("classes.frameroute:new missing object!"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        let frame: TermFrame = try_unwrap_frame(
 | 
			
		||||
            ctx,
 | 
			
		||||
            &stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("classes.frameroute:new missing frame!"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        // We re-intern it to ensure we always point at the userdata.
 | 
			
		||||
        let frame = intern_id(ctx, frame);
 | 
			
		||||
 | 
			
		||||
        frameroute.set(ctx, ctx.intern_static(b"frame"), frame)?;
 | 
			
		||||
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(super) fn frameroute_route<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    global_memo: &GlobalMemoCell,
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    let global_memo = global_memo.clone();
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let frameroute = Table::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("frameroute:route called without self!"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        let line = piccolo::String::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("frameroute:route called without line!"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        let frame: TermFrame =
 | 
			
		||||
            try_unwrap_frame(ctx, &frameroute.get(ctx, ctx.intern_static(b"frame"))?)?;
 | 
			
		||||
 | 
			
		||||
        // We ignore errors with the term frame to avoid breaking the entire client for one closed frame.
 | 
			
		||||
        echo_to_term_frame(&global_memo, &frame, &String::from_utf8_lossy(&line)).unwrap_or(());
 | 
			
		||||
        Ok(CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@ -151,7 +151,7 @@ pub fn panel_merge<'gc>(
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn try_unwrap_frame<'gc>(
 | 
			
		||||
pub fn try_unwrap_frame<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    value: &Value<'gc>,
 | 
			
		||||
) -> Result<TermFrame, piccolo::Error<'gc>> {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
use anyhow::Error;
 | 
			
		||||
use gc_arena::{Gc, Rootable};
 | 
			
		||||
use piccolo::{
 | 
			
		||||
    self, Callback, CallbackReturn, Context, FromValue, Function, IntoValue, StashedValue, Table,
 | 
			
		||||
    UserData, Value,
 | 
			
		||||
    self, async_sequence, meta_ops, Callback, CallbackReturn, Context, FromValue, Function,
 | 
			
		||||
    IntoValue, MetaMethod, SequenceReturn, StashedValue, Table, UserData, Value,
 | 
			
		||||
};
 | 
			
		||||
use wasm_bindgen::JsValue;
 | 
			
		||||
use web_sys::console;
 | 
			
		||||
@ -16,7 +16,7 @@ use crate::{
 | 
			
		||||
    GlobalLayoutCell, GlobalMemoCell,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::LuaState;
 | 
			
		||||
use super::{prep_metaop_call, LuaState};
 | 
			
		||||
 | 
			
		||||
fn try_unwrap_socketid<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
@ -163,10 +163,49 @@ pub(super) fn connect_mud<'gc>(
 | 
			
		||||
 | 
			
		||||
        muds.set(ctx, name, new_socket)?;
 | 
			
		||||
 | 
			
		||||
        let mud_class: Table = ctx
 | 
			
		||||
            .get_global::<Table>("classes")?
 | 
			
		||||
            .get(ctx, ctx.intern_static(b"mud"))?;
 | 
			
		||||
 | 
			
		||||
        let conntab = Table::new(&ctx);
 | 
			
		||||
        muds.set(ctx, new_socket, conntab)?;
 | 
			
		||||
        conntab.set(ctx, ctx.intern_static(b"socket"), new_socket)?;
 | 
			
		||||
        conntab.set(ctx, ctx.intern_static(b"buffer"), ctx.intern_static(b""))?;
 | 
			
		||||
        let conntab_meta = Table::new(&ctx);
 | 
			
		||||
        conntab_meta.set(ctx, MetaMethod::Index, mud_class)?;
 | 
			
		||||
        conntab.set_metatable(&ctx, Some(conntab_meta));
 | 
			
		||||
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
        let seq = async_sequence(&ctx, |locals, mut seq| {
 | 
			
		||||
            let conntab = locals.stash(&ctx, conntab);
 | 
			
		||||
            async move {
 | 
			
		||||
                let call = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                    let conntab = locals.fetch(&conntab);
 | 
			
		||||
                    stack.consume(ctx)?;
 | 
			
		||||
                    Ok(prep_metaop_call(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        stack,
 | 
			
		||||
                        locals,
 | 
			
		||||
                        meta_ops::index(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            conntab.into_value(ctx),
 | 
			
		||||
                            ctx.intern_static(b"new").into_value(ctx),
 | 
			
		||||
                        )?,
 | 
			
		||||
                    ))
 | 
			
		||||
                })?;
 | 
			
		||||
                if let Some(call) = call {
 | 
			
		||||
                    seq.call(&call, 0).await?;
 | 
			
		||||
                }
 | 
			
		||||
                let new_fn = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                    let new_fn: Function = stack.consume(ctx)?;
 | 
			
		||||
                    stack.push_back(locals.fetch(&conntab).into_value(ctx));
 | 
			
		||||
                    Ok(locals.stash(&ctx, new_fn))
 | 
			
		||||
                })?;
 | 
			
		||||
                seq.call(&new_fn, 0).await?;
 | 
			
		||||
                Ok(SequenceReturn::Return)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Sequence(seq))
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -257,16 +296,59 @@ pub(super) fn mudoutput<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -
 | 
			
		||||
                .as_bytes();
 | 
			
		||||
        let mut cur_buf: Vec<u8> = [buf, output].concat();
 | 
			
		||||
 | 
			
		||||
        let handlers = Table::from_value(ctx, ctx.get_global("handlers")?)?;
 | 
			
		||||
 | 
			
		||||
        let mut fns: Vec<(&'static [u8], Vec<StashedValue>)> = vec![];
 | 
			
		||||
        let mut fns: Vec<(&'static [u8], Vec<Value>)> = vec![];
 | 
			
		||||
        loop {
 | 
			
		||||
            match parse_telnet_buf(&cur_buf) {
 | 
			
		||||
                (new_buf, None) => {
 | 
			
		||||
                    conntab.set(ctx, ctx.intern_static(b"buffer"), ctx.intern(&new_buf))?;
 | 
			
		||||
 | 
			
		||||
                    let seq = piccolo::async_sequence(&ctx, |locals, seq| async {
 | 
			
		||||
                        Ok(piccolo::SequenceReturn::Return)
 | 
			
		||||
                    let seq = piccolo::async_sequence(&ctx, |locals, mut seq| {
 | 
			
		||||
                        let conntab = locals.stash(&ctx, conntab);
 | 
			
		||||
                        let fns: Vec<(&'static [u8], Vec<StashedValue>)> = fns
 | 
			
		||||
                            .into_iter()
 | 
			
		||||
                            .map(|fnv| {
 | 
			
		||||
                                (
 | 
			
		||||
                                    fnv.0,
 | 
			
		||||
                                    fnv.1.into_iter().map(|v| locals.stash(&ctx, v)).collect(),
 | 
			
		||||
                                )
 | 
			
		||||
                            })
 | 
			
		||||
                            .collect();
 | 
			
		||||
                        async move {
 | 
			
		||||
                            for (func_name, params) in fns {
 | 
			
		||||
                                let call =
 | 
			
		||||
                                    seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                                        let conntab = locals.fetch(&conntab);
 | 
			
		||||
                                        stack.consume(ctx)?;
 | 
			
		||||
                                        Ok(prep_metaop_call(
 | 
			
		||||
                                            ctx,
 | 
			
		||||
                                            stack,
 | 
			
		||||
                                            locals,
 | 
			
		||||
                                            meta_ops::index(
 | 
			
		||||
                                                ctx,
 | 
			
		||||
                                                conntab.into_value(ctx),
 | 
			
		||||
                                                ctx.intern_static(func_name).into_value(ctx),
 | 
			
		||||
                                            )?,
 | 
			
		||||
                                        ))
 | 
			
		||||
                                    })?;
 | 
			
		||||
                                if let Some(call) = call {
 | 
			
		||||
                                    seq.call(&call, 0).await?;
 | 
			
		||||
                                }
 | 
			
		||||
                                let call = seq.try_enter(|ctx, locals, _, mut stack| {
 | 
			
		||||
                                    let value = stack.pop_back().ok_or_else(|| {
 | 
			
		||||
                                        anyhow::Error::msg("Index didn't return value")
 | 
			
		||||
                                    })?;
 | 
			
		||||
                                    stack.consume(ctx)?;
 | 
			
		||||
                                    stack.push_back(locals.fetch(&conntab).into_value(ctx));
 | 
			
		||||
                                    for param in ¶ms {
 | 
			
		||||
                                        stack.push_back(locals.fetch(param));
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    Ok(locals.stash(&ctx, Function::from_value(ctx, value)?))
 | 
			
		||||
                                })?;
 | 
			
		||||
                                seq.call(&call, 0).await?;
 | 
			
		||||
                            }
 | 
			
		||||
                            Ok(piccolo::SequenceReturn::Return)
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    return Ok(piccolo::CallbackReturn::Sequence(seq));
 | 
			
		||||
@ -274,47 +356,32 @@ pub(super) fn mudoutput<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -
 | 
			
		||||
                (new_buf, Some(cmd)) => {
 | 
			
		||||
                    cur_buf = new_buf;
 | 
			
		||||
                    match cmd {
 | 
			
		||||
                        TelnetOutput::Line(l) => fns.push((
 | 
			
		||||
                            b"mudoutput_line",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(ctx.intern(&l).into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Prompt(p) => fns.push((
 | 
			
		||||
                            b"mudoutput_prompt",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(ctx.intern(&p).into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Line(l) => {
 | 
			
		||||
                            fns.push((b"mudoutput_line", vec![ctx.intern(&l).into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Prompt(p) => {
 | 
			
		||||
                            fns.push((b"mudoutput_prompt", vec![ctx.intern(&p).into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Nop => {}
 | 
			
		||||
                        TelnetOutput::Break => fns.push((b"mudoutput_break", vec![ctx.stash(mud)])),
 | 
			
		||||
                        TelnetOutput::Sync => fns.push((b"mudoutput_sync", vec![ctx.stash(mud)])),
 | 
			
		||||
                        TelnetOutput::Interrupt => {
 | 
			
		||||
                            fns.push((b"mudoutput_interrupt", vec![ctx.stash(mud)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Break => fns.push((b"mudoutput_break", vec![])),
 | 
			
		||||
                        TelnetOutput::Sync => fns.push((b"mudoutput_sync", vec![])),
 | 
			
		||||
                        TelnetOutput::Interrupt => fns.push((b"mudoutput_interrupt", vec![])),
 | 
			
		||||
 | 
			
		||||
                        TelnetOutput::AbortOutput => {
 | 
			
		||||
                            fns.push((b"mudoutput_abort_output", vec![ctx.stash(mud)]))
 | 
			
		||||
                        TelnetOutput::AbortOutput => fns.push((b"mudoutput_abort_output", vec![])),
 | 
			
		||||
                        TelnetOutput::AreYouThere => fns.push((b"mudoutput_areyouthere", vec![])),
 | 
			
		||||
                        TelnetOutput::Will(v) => {
 | 
			
		||||
                            fns.push((b"mudoutput_will", vec![v.into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::AreYouThere => {
 | 
			
		||||
                            fns.push((b"mudoutput_areyouthere", vec![ctx.stash(mud)]))
 | 
			
		||||
                        TelnetOutput::Wont(v) => {
 | 
			
		||||
                            fns.push((b"mudoutput_wont", vec![v.into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Do(v) => fns.push((b"mudoutput_do", vec![v.into_value(ctx)])),
 | 
			
		||||
                        TelnetOutput::Dont(v) => {
 | 
			
		||||
                            fns.push((b"mudoutput_dont", vec![v.into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Subnegotiation(t) => {
 | 
			
		||||
                            fns.push((b"mudoutput_subnegotiation", vec![t.into_value(ctx)]))
 | 
			
		||||
                        }
 | 
			
		||||
                        TelnetOutput::Will(v) => fns.push((
 | 
			
		||||
                            b"mudoutput_will",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(v.into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Wont(v) => fns.push((
 | 
			
		||||
                            b"mudoutput_wont",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(v.into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Do(v) => fns.push((
 | 
			
		||||
                            b"mudoutput_do",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(v.into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Dont(v) => fns.push((
 | 
			
		||||
                            b"mudoutput_dont",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(v.into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                        TelnetOutput::Subnegotiation(t) => fns.push((
 | 
			
		||||
                            b"mudoutput_subnegotiation",
 | 
			
		||||
                            vec![ctx.stash(mud), ctx.stash(t.into_value(ctx))],
 | 
			
		||||
                        )),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -326,7 +393,61 @@ pub(super) fn mudoutput_line<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    _global_memo: &GlobalMemoCell,
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    Callback::from_fn(&ctx, move |_ctx, _ex, _stack| Ok(CallbackReturn::Return))
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let mud = Table::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("Missing muds:mudoutput_line self"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        let line = piccolo::String::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("Missing muds:mudoutput_line line"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        let frameroutes: Table = mud.get(ctx, "frameroutes")?;
 | 
			
		||||
 | 
			
		||||
        let seq = async_sequence(&ctx, |locals, mut seq| {
 | 
			
		||||
            let frameroutes: Vec<StashedValue> = frameroutes
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|fr| locals.stash(&ctx, fr.1))
 | 
			
		||||
                .collect();
 | 
			
		||||
            let line = locals.stash(&ctx, line);
 | 
			
		||||
            async move {
 | 
			
		||||
                for frameroute in frameroutes {
 | 
			
		||||
                    let call = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                        let frameroute = locals.fetch(&frameroute);
 | 
			
		||||
                        stack.consume(ctx)?;
 | 
			
		||||
                        Ok(prep_metaop_call(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            stack,
 | 
			
		||||
                            locals,
 | 
			
		||||
                            meta_ops::index(
 | 
			
		||||
                                ctx,
 | 
			
		||||
                                frameroute.into_value(ctx),
 | 
			
		||||
                                ctx.intern_static(b"route").into_value(ctx),
 | 
			
		||||
                            )?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })?;
 | 
			
		||||
                    if let Some(call) = call {
 | 
			
		||||
                        seq.call(&call, 0).await?;
 | 
			
		||||
                    }
 | 
			
		||||
                    let route_fn = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                        let route_fn: Function = stack.consume(ctx)?;
 | 
			
		||||
                        stack.push_back(locals.fetch(&frameroute).into_value(ctx));
 | 
			
		||||
                        stack.push_back(locals.fetch(&line).into_value(ctx));
 | 
			
		||||
                        Ok(locals.stash(&ctx, route_fn))
 | 
			
		||||
                    })?;
 | 
			
		||||
                    seq.call(&route_fn, 0).await?;
 | 
			
		||||
                }
 | 
			
		||||
                Ok(SequenceReturn::Return)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(CallbackReturn::Sequence(seq))
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
pub(super) fn mudoutput_prompt<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
@ -361,3 +482,63 @@ pub(super) fn mudoutput_subnegotiation<'gc>(
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    Callback::from_fn(&ctx, move |_ctx, _ex, _stack| Ok(CallbackReturn::Return))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(super) fn new_mud<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -> Callback<'gc> {
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let mud: Table = Table::from_value(
 | 
			
		||||
            ctx,
 | 
			
		||||
            stack
 | 
			
		||||
                .pop_front()
 | 
			
		||||
                .ok_or_else(|| anyhow::Error::msg("classes.mud:new missing object!"))?,
 | 
			
		||||
        )?;
 | 
			
		||||
        let frameroutes: Table = Table::new(&ctx);
 | 
			
		||||
        let frameroute: Table = Table::new(&ctx);
 | 
			
		||||
        frameroutes.set(ctx, 0, frameroute)?;
 | 
			
		||||
        frameroute.set_metatable(
 | 
			
		||||
            &ctx,
 | 
			
		||||
            Some(
 | 
			
		||||
                ctx.get_global::<Table>("classes")?
 | 
			
		||||
                    .get(ctx, ctx.intern_static(b"frameroute"))?,
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
        mud.set(ctx, ctx.intern_static(b"frameroutes"), frameroutes)?;
 | 
			
		||||
 | 
			
		||||
        // And call new on the frameroute, for the current frame.
 | 
			
		||||
        let seq = async_sequence(&ctx, |locals, mut seq| {
 | 
			
		||||
            let frameroute = locals.stash(&ctx, frameroute);
 | 
			
		||||
            async move {
 | 
			
		||||
                let call = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                    let frameroute = locals.fetch(&frameroute);
 | 
			
		||||
                    stack.consume(ctx)?;
 | 
			
		||||
                    Ok(prep_metaop_call(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        stack,
 | 
			
		||||
                        locals,
 | 
			
		||||
                        meta_ops::index(
 | 
			
		||||
                            ctx,
 | 
			
		||||
                            frameroute.into_value(ctx),
 | 
			
		||||
                            ctx.intern_static(b"new").into_value(ctx),
 | 
			
		||||
                        )?,
 | 
			
		||||
                    ))
 | 
			
		||||
                })?;
 | 
			
		||||
                if let Some(call) = call {
 | 
			
		||||
                    seq.call(&call, 0).await?;
 | 
			
		||||
                }
 | 
			
		||||
                let new_fn = seq.try_enter(|ctx, locals, _execution, mut stack| {
 | 
			
		||||
                    let new_fn: Function = stack.consume(ctx)?;
 | 
			
		||||
                    stack.push_back(locals.fetch(&frameroute).into_value(ctx));
 | 
			
		||||
                    stack.push_back(
 | 
			
		||||
                        ctx.get_global::<Table>("info")?
 | 
			
		||||
                            .get(ctx, ctx.intern_static(b"current_frame"))?,
 | 
			
		||||
                    );
 | 
			
		||||
                    Ok(locals.stash(&ctx, new_fn))
 | 
			
		||||
                })?;
 | 
			
		||||
                seq.call(&new_fn, 0).await?;
 | 
			
		||||
 | 
			
		||||
                Ok(SequenceReturn::Return)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Sequence(seq))
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -120,9 +120,6 @@ fn get_or_make_term_frame<'a>(
 | 
			
		||||
        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 {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user