Fix(app::command_interface): Provide pre-generated file, to check syntax

This commit is contained in:
Benedikt Peetz 2023-07-23 16:35:18 +02:00
parent ebb16a20de
commit 189ae509f8
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
2 changed files with 115 additions and 55 deletions

View File

@ -0,0 +1,54 @@
// FIXME: This file needs documentation with examples of how the proc macros work.
// for now use `cargo expand app::command_interface` for an overview
use std::{io::{Error, ErrorKind}, sync::Arc};
use lua_macros::{ci_command, turn_struct_to_ci_command_enum};
use crate::app::event_types::Event;
/// This struct is here to guarantee, that all functions actually end up in the lua context.
/// I.e. Rust should throw a compile error, when one field is added, but not a matching function.
///
/// What it does:
/// - Generates a `generate_ci_functions` function, which wraps the specified rust in functions
/// in lua and exports them to the globals in the context provided as argument.
/// - Generates a Commands enum, which contains every Camel cased version of the fields.
///
/// Every command specified here should have a function named $command_name, where $command_name is the snake cased name of the field.
///
/// This function is exported to the lua context, thus it's signature must be:
/// ```rust
/// fn $command_name(context: Context, input_string: String) -> Result<$return_type, rlua::Error> {}
/// ```
/// where $return_type is the type returned by the function (the only supported ones are right now
/// `String` and `()`).
#[turn_struct_to_ci_command_enum]
struct Commands {
/// Greets the user
greet: fn(String) -> String,
/// Closes the application
//#[expose(lua)]
exit: fn(),
/// Shows the command line
command_line_show: fn(),
/// Hides the command line
command_line_hide: fn(),
/// Go to the next plane
cycle_planes: fn(),
/// Go to the previous plane
cycle_planes_rev: fn(),
/// Sets the current app mode to Normal / navigation mode
set_mode_normal: fn(),
/// Sets the current app mode to Insert / editing mode
set_mode_insert: fn(),
/// Send a message to the current room
/// The send message is interpreted literally.
room_message_send: fn(String) -> String,
}

View File

@ -1,57 +1,63 @@
// FIXME: This file needs documentation with examples of how the proc macros work. use cli_log::debug;
// for now use `cargo expand app::command_interface` for an overview
use std::{ #[derive(Debug)]
io::{Error, ErrorKind}, pub enum Command {
sync::Arc, Greet(String),
}; Exit,
CommandLineShow,
use lua_macros::{ci_command, turn_struct_to_ci_command_enum}; CommandLineHide,
CyclePlanes,
use crate::app::event_types::Event; CyclePlanesRev,
/// This struct is here to guarantee, that all functions actually end up in the lua context. RoomMessageSend(String),
/// I.e. Rust should throw a compile error, when one field is added, but not a matching function. Help(Option<String>),
/// }
/// What it does:
/// - Generates a `generate_ci_functions` function, which wraps the specified rust in functions pub fn generate_ci_functions(
/// in lua and exports them to the globals in the context provided as argument. lua: mlua::Lua,
/// - Generates a Commands enum, which contains every Camel cased version of the fields. tx: tokio::sync::mpsc::Sender<crate::app::events::event_types::Event>,
/// ) -> mlua::Lua {
/// Every command specified here should have a function named $command_name, where $command_name is the snake cased name of the field. lua.set_app_data(tx);
/// let globals = lua.globals();
/// This function is exported to the lua context, thus it's signature must be: let fun_greet = lua.create_async_function(greet).expect(&{
/// ```rust let res = format!("The function: `{}` should be defined", "greet");
/// fn $command_name(context: Context, input_string: String) -> Result<$return_type, rlua::Error> {} res
/// ``` });
/// where $return_type is the type returned by the function (the only supported ones are right now globals.set("greet", fun_greet).expect(&{
/// `String` and `()`). let res = format!(
"Setting a static global value ({}, fun_{}) should work",
#[turn_struct_to_ci_command_enum] "greet", "greet",
struct Commands { );
/// Greets the user res
greet: fn(String) -> String, });
/// Closes the application drop(globals);
//#[expose(lua)] lua
exit: fn(), }
/// Shows the command line async fn greet(lua: &mlua::Lua, input: String) -> Result<String, mlua::Error> {
command_line_show: fn(), let (callback_tx, mut callback_rx) = tokio::sync::mpsc::channel::<String>(256);
let tx: core::cell::Ref<tokio::sync::mpsc::Sender<crate::app::events::event_types::Event>> =
/// Hides the command line lua.app_data_ref().expect("This exists, it was set before");
command_line_hide: fn(),
debug!("Got tx");
/// Go to the next plane (*tx)
cycle_planes: fn(), .try_send(crate::app::events::event_types::Event::CommandEvent(
/// Go to the previous plane Command::Greet(input.clone()),
cycle_planes_rev: fn(), Some(callback_tx),
))
/// Sets the current app mode to Normal / navigation mode .expect("This should work, as the reciever is not dropped");
set_mode_normal: fn(),
/// Sets the current app mode to Insert / editing mode debug!("Sent CommandEvent");
set_mode_insert: fn(),
debug!("Returning output...");
/// Send a message to the current room if let Some(output) = callback_rx.recv().await {
/// The send message is interpreted literally. callback_rx.close();
room_message_send: fn(String) -> String, debug!("returned output");
return Ok(output);
} else {
debug!("Not returning output...");
return Err(mlua::Error::ExternalError(std::sync::Arc::new(
std::io::Error::new(std::io::ErrorKind::Other, "Callback reciever dropped"),
)));
}
} }