Feat(command_interface): Add basic lua support
This commit is contained in:
parent
ef5afcda02
commit
327450c64b
|
@ -140,7 +140,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -151,7 +151,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -269,6 +269,15 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.13.0"
|
version = "3.13.0"
|
||||||
|
@ -642,7 +651,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -841,7 +850,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1278,6 +1287,15 @@ dependencies = [
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lua_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.64",
|
||||||
|
"quote 1.0.29",
|
||||||
|
"syn 2.0.25",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maplit"
|
name = "maplit"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -1586,7 +1604,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1701,7 +1719,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2097,6 +2115,30 @@ dependencies = [
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rlua"
|
||||||
|
version = "0.19.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d33e5ba15c3d43178f283ed5863d4531e292fc0e56fb773f3bea45f18e3a42a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"bstr",
|
||||||
|
"libc",
|
||||||
|
"num-traits",
|
||||||
|
"rlua-lua54-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rlua-lua54-sys"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7aafabafe1895cb4a2be81a56d7ff3d46bf4b5d2f9cfdbea2ed404cdabe96474"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma"
|
name = "ruma"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
@ -2286,7 +2328,7 @@ checksum = "27738cfea0d944ab72c3ed01f3d5f23ec4322af8a1431e40ce630e4c01ea74fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2458,9 +2500,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.24"
|
version = "2.0.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36ccaf716a23c35ff908f91c971a86a9a71af5998c1d8f10e828d9f55f68ac00"
|
checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
|
@ -2498,7 +2540,7 @@ checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2553,7 +2595,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2632,7 +2674,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2652,7 +2694,9 @@ dependencies = [
|
||||||
"cli-log",
|
"cli-log",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"indexmap 2.0.0",
|
"indexmap 2.0.0",
|
||||||
|
"lua_macros",
|
||||||
"matrix-sdk",
|
"matrix-sdk",
|
||||||
|
"rlua",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
@ -2870,7 +2914,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2904,7 +2948,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
@ -3090,5 +3134,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.64",
|
"proc-macro2 1.0.64",
|
||||||
"quote 1.0.29",
|
"quote 1.0.29",
|
||||||
"syn 2.0.24",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,6 +7,7 @@ license = "MIT"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
lua_macros = { path = "./lua_macros" }
|
||||||
tui = "0.19"
|
tui = "0.19"
|
||||||
tui-textarea = { version = "0.2", features = ["crossterm"] }
|
tui-textarea = { version = "0.2", features = ["crossterm"] }
|
||||||
crossterm = "0.25"
|
crossterm = "0.25"
|
||||||
|
@ -17,3 +18,4 @@ tokio-util = "0.7"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
cli-log = "2.0"
|
cli-log = "2.0"
|
||||||
indexmap = "2.0.0"
|
indexmap = "2.0.0"
|
||||||
|
rlua = "0.19.7"
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
rust-stable
|
rust-stable
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
cargo-edit
|
cargo-edit
|
||||||
|
cargo-expand
|
||||||
];
|
];
|
||||||
inherit nativeBuildInputs buildInputs;
|
inherit nativeBuildInputs buildInputs;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# build
|
||||||
|
/target
|
||||||
|
/result
|
||||||
|
|
||||||
|
# lua_macros is a library
|
||||||
|
Cargo.lock
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "lua_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate_type = ["proc-macro"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0.64"
|
||||||
|
quote = "1.0.29"
|
||||||
|
syn = "2.0.25"
|
|
@ -0,0 +1,59 @@
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn;
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn generate_ci_functions(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
// Construct a representation of Rust code as a syntax tree
|
||||||
|
// that we can manipulate
|
||||||
|
let input = syn::parse(input)
|
||||||
|
.expect("This should always be valid rust code, as it's extracted from direct code");
|
||||||
|
|
||||||
|
// Build the trait implementation
|
||||||
|
generate_generate_ci_functions(&input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_generate_ci_functions(input: &syn::DeriveInput) -> TokenStream {
|
||||||
|
let input_tokens: TokenStream2 = match &input.data {
|
||||||
|
syn::Data::Struct(input) => match &input.fields {
|
||||||
|
syn::Fields::Named(named_fields) => named_fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| -> TokenStream2 {
|
||||||
|
let field_ident = field.ident.as_ref().expect(
|
||||||
|
"These are only the named field, thus they all should have a name.",
|
||||||
|
);
|
||||||
|
let function_name_ident = format_ident!("fun_{}", field_ident);
|
||||||
|
let function_name = format!("{}", field_ident);
|
||||||
|
quote! {
|
||||||
|
let #function_name_ident = context.create_function(#field_ident).expect(
|
||||||
|
&format!(
|
||||||
|
"The function: `{}` should be defined",
|
||||||
|
#function_name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
globals.set(#function_name, #function_name_ident).expect(
|
||||||
|
&format!(
|
||||||
|
"Setting a static global value ({}, fun_{}) should work",
|
||||||
|
#function_name,
|
||||||
|
#function_name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
_ => unimplemented!("Only implemented for named fileds"),
|
||||||
|
},
|
||||||
|
_ => unimplemented!("Only for implemented for structs"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let gen = quote! {
|
||||||
|
pub fn generate_ci_functions(context: &mut Context) {
|
||||||
|
let globals = context.globals();
|
||||||
|
#input_tokens
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gen.into()
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
use lua_macros::generate_ci_functions;
|
||||||
|
use rlua::Context;
|
||||||
|
|
||||||
|
// This struct is here to gurantee, 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.
|
||||||
|
#[generate_ci_functions()]
|
||||||
|
struct Commands<'lua> {
|
||||||
|
greet: Function<'lua>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn greet(context: Context, name: String) -> Result<String, rlua::Error> {
|
||||||
|
Ok(format!("Name is {}", name))
|
||||||
|
}
|
|
@ -136,7 +136,42 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ui::MainInputPosition::CLI => {
|
ui::MainInputPosition::CLI => {
|
||||||
todo!();
|
if let Some(_) = app.ui.cli {
|
||||||
|
match input {
|
||||||
|
CrosstermEvent::Key(KeyEvent {
|
||||||
|
code: KeyCode::Enter,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let cli_event = app.ui
|
||||||
|
.cli
|
||||||
|
.as_mut()
|
||||||
|
.expect("This is already checked")
|
||||||
|
.lines()
|
||||||
|
.get(0)
|
||||||
|
.expect(
|
||||||
|
"There can only be one line in the buffer, as we collect it on enter being inputted"
|
||||||
|
)
|
||||||
|
.to_owned();
|
||||||
|
let output = app.handle_ci_event(&cli_event).await?;
|
||||||
|
|
||||||
|
// delete the old text:
|
||||||
|
|
||||||
|
// We can use a mutable borrow now, as we should only need one
|
||||||
|
let cli = app.ui.cli.as_mut().expect("Checked above");
|
||||||
|
cli.move_cursor(tui_textarea::CursorMove::Jump(0, 0));
|
||||||
|
cli.delete_str(0, cli_event.chars().count());
|
||||||
|
assert!(cli.is_empty());
|
||||||
|
cli.insert_str(output);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
app.ui
|
||||||
|
.cli
|
||||||
|
.as_mut()
|
||||||
|
.expect("This is already checked")
|
||||||
|
.input(tui_textarea::Input::from(input.to_owned()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,10 +26,21 @@ pub struct App<'ui> {
|
||||||
channel_rx: mpsc::Receiver<event_types::Event>,
|
channel_rx: mpsc::Receiver<event_types::Event>,
|
||||||
input_listener_killer: CancellationToken,
|
input_listener_killer: CancellationToken,
|
||||||
matrix_listener_killer: CancellationToken,
|
matrix_listener_killer: CancellationToken,
|
||||||
|
|
||||||
|
lua: Lua,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App<'_> {
|
impl App<'_> {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
|
fn set_up_lua() -> Lua {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
lua.context(|mut lua_context| {
|
||||||
|
generate_ci_functions(&mut lua_context);
|
||||||
|
});
|
||||||
|
lua
|
||||||
|
}
|
||||||
|
|
||||||
let path: &std::path::Path = Path::new("userdata/accounts.json");
|
let path: &std::path::Path = Path::new("userdata/accounts.json");
|
||||||
let config = if path.exists() {
|
let config = if path.exists() {
|
||||||
info!("Reading account config (userdata/accounts.json)");
|
info!("Reading account config (userdata/accounts.json)");
|
||||||
|
@ -49,9 +60,26 @@ impl App<'_> {
|
||||||
channel_rx,
|
channel_rx,
|
||||||
input_listener_killer: CancellationToken::new(),
|
input_listener_killer: CancellationToken::new(),
|
||||||
matrix_listener_killer: CancellationToken::new(),
|
matrix_listener_killer: CancellationToken::new(),
|
||||||
|
|
||||||
|
lua: set_up_lua(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_ci_event(&self, event: &str) -> Result<String> {
|
||||||
|
info!("Recieved ci event: `{event}`; executing..");
|
||||||
|
|
||||||
|
// TODO: Should the ci support more than strings?
|
||||||
|
let output = self.lua.context(|context| -> Result<String> {
|
||||||
|
let output = context
|
||||||
|
.load(&event)
|
||||||
|
.eval::<String>()
|
||||||
|
.with_context(|| format!("Failed to execute: `{event}`"))?;
|
||||||
|
info!("Function evaluated to: `{output}`");
|
||||||
|
Ok(output)
|
||||||
|
})?;
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) -> Result<()> {
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
// Spawn input event listener
|
// Spawn input event listener
|
||||||
tokio::task::spawn(events::poll_input_events(
|
tokio::task::spawn(events::poll_input_events(
|
||||||
|
|
Reference in New Issue