From 972b7c0cabb48cae9503e12e18edc94587036981 Mon Sep 17 00:00:00 2001 From: Condorra Date: Sat, 17 Aug 2024 21:36:15 +1000 Subject: [PATCH] Implement echo to current frame + raw echo without CRLF --- src/command_handler.rs | 1 + src/lua_state.rs | 79 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/command_handler.rs b/src/command_handler.rs index b495525..32e6c97 100644 --- a/src/command_handler.rs +++ b/src/command_handler.rs @@ -11,6 +11,7 @@ fn reentrant_command_handler( command_in: &str, ) { echo_to_term_frame(globals, term_frame, "\r").unwrap_or(()); + lua_state.set_current_frame(term_frame); for command in parse_commands(command_in).commands { match command.split_out_command() { None => (), diff --git a/src/lua_state.rs b/src/lua_state.rs index 29ea643..5957cbe 100644 --- a/src/lua_state.rs +++ b/src/lua_state.rs @@ -1,5 +1,8 @@ use anyhow::Error; -use piccolo::{Callback, Closure, Context, Executor, IntoValue, Lua, StashedExecutor, Table}; +use piccolo::{ + Callback, Closure, Context, Executor, FromValue, Function, IntoValue, Lua, StashedExecutor, + StaticError, Table, +}; use crate::{echo_to_term_frame, GlobalCell, TermFrame}; use std::str; @@ -18,6 +21,20 @@ impl LuaState { Ok(LuaState { interp, exec }) } + fn try_set_current_frame(&mut self, frame: &TermFrame) -> Result<(), StaticError> { + self.interp.try_enter(|ctx| { + let info_table = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"info")))?; + info_table.set(ctx, ctx.intern_static(b"current_frame"), frame.0 as i64)?; + Ok(()) + }) + } + + pub fn set_current_frame(&mut self, frame: &TermFrame) { + // We silently ignore errors here. Failure can happen if the Lua code does weird things + // like messes with the info global, so better to just ignore. + self.try_set_current_frame(frame).unwrap_or(()) + } + pub fn execute(&mut self, command: &str) -> Result<(), String> { self.interp .try_enter(|ctx| { @@ -40,16 +57,30 @@ pub fn install_lua_globals(global: &GlobalCell) -> Result<(), String> { .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"))?; + macro_rules! register_command { + ($sym: ident) => { + cmd_table + .set( + ctx, + ctx.intern_static(stringify!($sym).as_bytes()), + $sym(ctx, global.clone()), + ) + .map_err(|_| Error::msg("Can't add command"))?; + }; + } + + register_command!(echo_frame_raw); + register_command!(echo_frame); + register_command!(echo); ctx.set_global(ctx.intern_static(b"commands").into_value(ctx), cmd_table) .map(|_| ()) .map_err(|_| Error::msg("Can't set commands key"))?; + + let info_table = Table::new(&ctx); + ctx.set_global(ctx.intern_static(b"info").into_value(ctx), info_table) + .map(|_| ()) + .map_err(|_| Error::msg("Can't set info key"))?; + Ok(()) }) .map_err(|e| e.to_string())?; @@ -57,7 +88,7 @@ pub fn install_lua_globals(global: &GlobalCell) -> Result<(), String> { Ok(()) } -fn echo_frame(ctx: Context, global: GlobalCell) -> Callback { +fn echo_frame_raw(ctx: Context, global: GlobalCell) -> Callback { Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { let frame_no: u64 = stack.from_front(ctx)?; let message: piccolo::String = stack.from_front(ctx)?; @@ -68,3 +99,33 @@ fn echo_frame(ctx: Context, global: GlobalCell) -> Callback { Ok(piccolo::CallbackReturn::Return) }) } + +fn echo_frame<'gc>(ctx: Context<'gc>, _global: GlobalCell) -> Callback<'gc> { + Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { + let commands: Table<'gc> = + Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"commands")))?; + let function = Function::from_value(ctx, commands.get(ctx, "echo_frame_raw"))?; + let message: piccolo::Value = stack.from_back(ctx)?; + let message = ctx.intern(&format!("{}\r\n", message).as_bytes()); + stack.push_back(message.into()); + Ok(piccolo::CallbackReturn::Call { + function, + then: None, + }) + }) +} + +fn echo<'gc>(ctx: Context<'gc>, _global: GlobalCell) -> Callback<'gc> { + Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { + let commands: Table<'gc> = + Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"commands")))?; + let function = Function::from_value(ctx, commands.get(ctx, "echo_frame"))?; + let info: Table<'gc> = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"info")))?; + let cur_frame = info.get(ctx, ctx.intern_static(b"current_frame")); + stack.push_front(cur_frame); + Ok(piccolo::CallbackReturn::Call { + function, + then: None, + }) + }) +}