From c2bd68029908c5146da5a825f1796a561e4900c1 Mon Sep 17 00:00:00 2001 From: Condorra Date: Sat, 17 Aug 2024 23:19:41 +1000 Subject: [PATCH] Allow defining commands in Lua, and executing them. --- src/command_handler.rs | 32 +++++++++++++++++++++++++------ src/lua_state.rs | 43 ++++++++++++++++++++++++++++++++++++++---- src/term_view.rs | 5 ++--- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/command_handler.rs b/src/command_handler.rs index 32e6c97..43f6e0a 100644 --- a/src/command_handler.rs +++ b/src/command_handler.rs @@ -4,6 +4,15 @@ use crate::{ echo_to_term_frame, lua_state::LuaState, parsing::parse_commands, GlobalCell, TermFrame, }; +fn debrace(inp: &str) -> &str { + let v = inp.trim(); + if v.starts_with("{") && v.ends_with("}") { + &v[1..(v.len() - 1)] + } else { + v + } +} + fn reentrant_command_handler( lua_state: &mut LuaState, globals: &GlobalCell, @@ -16,12 +25,23 @@ fn reentrant_command_handler( match command.split_out_command() { None => (), Some((cmd, rest)) => { - if cmd == "##" { - match lua_state.execute(&join(rest.arguments.iter(), " ")) { - Ok(()) => (), - Err(msg) => { - echo_to_term_frame(globals, term_frame, &format!("{}\r\n", msg)) - .unwrap_or(()) + if cmd.starts_with('#') { + if cmd == "##" { + match lua_state.execute(debrace(&join(rest.arguments.iter(), " "))) { + Ok(()) => (), + Err(msg) => { + echo_to_term_frame(globals, term_frame, &format!("{}\r\n", msg)) + .unwrap_or(()) + } + } + } else { + let cmd = &cmd[1..]; + match lua_state.execute_command(cmd, &rest.arguments) { + Ok(()) => (), + Err(msg) => { + echo_to_term_frame(globals, term_frame, &format!("{}\r\n", msg)) + .unwrap_or(()) + } } } } diff --git a/src/lua_state.rs b/src/lua_state.rs index 5957cbe..a9bc73b 100644 --- a/src/lua_state.rs +++ b/src/lua_state.rs @@ -1,11 +1,11 @@ use anyhow::Error; use piccolo::{ Callback, Closure, Context, Executor, FromValue, Function, IntoValue, Lua, StashedExecutor, - StaticError, Table, + StaticError, Table, Value, Variadic, }; use crate::{echo_to_term_frame, GlobalCell, TermFrame}; -use std::str; +use std::{collections::VecDeque, str}; pub struct LuaState { pub interp: Lua, @@ -48,6 +48,35 @@ impl LuaState { .execute::<()>(&self.exec) .map_err(|err| format!("{}", err)) } + + pub fn execute_command( + &mut self, + command: &str, + arguments: &VecDeque<&str>, + ) -> Result<(), String> { + self.interp + .try_enter(|ctx| { + let commands = + Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"commands")))?; + let command_fn = + Function::from_value(ctx, commands.get(ctx, ctx.intern(command.as_bytes())))?; + ctx.fetch(&self.exec).restart( + ctx, + command_fn, + Variadic( + arguments + .iter() + .map(|s| ctx.intern(s.as_bytes()).into()) + .collect::>(), + ), + ); + Ok(()) + }) + .map_err(|err| format!("{}", err))?; + self.interp + .execute::<()>(&self.exec) + .map_err(|err| format!("{}", err)) + } } pub fn install_lua_globals(global: &GlobalCell) -> Result<(), String> { @@ -105,8 +134,14 @@ fn echo_frame<'gc>(ctx: Context<'gc>, _global: GlobalCell) -> Callback<'gc> { 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()); + let frame_no: Value = stack.pop_front(); + let all_parts: Vec = stack + .consume::>>(ctx)? + .into_iter() + .map(|v| format!("{}", v)) + .collect(); + stack.push_front(frame_no); + let message = ctx.intern((all_parts.join(" ") + "\r\n").as_bytes()); stack.push_back(message.into()); Ok(piccolo::CallbackReturn::Call { function, diff --git a/src/term_view.rs b/src/term_view.rs index 1a6f84a..4c19b5c 100644 --- a/src/term_view.rs +++ b/src/term_view.rs @@ -121,8 +121,7 @@ fn get_or_make_term_frame<'a>( ) }), initial_size, - ) - .into(), + ), retained_closures: None, }; @@ -207,7 +206,7 @@ pub fn echo_to_term_frame( .frame_registry .borrow() .get(frame_id) - .ok_or_else(|| "Attempt to echo to frame that doesn't exist.")? + .ok_or("Attempt to echo to frame that doesn't exist.")? .term .write(message); Ok(())