Compare commits

..

1 Commits

Author SHA1 Message Date
Benedikt Peetz 52b77aee4b
Todo: Rebase me! 2023-07-15 23:30:58 +02:00
16 changed files with 126 additions and 309 deletions

10
Cargo.lock generated
View File

@ -415,6 +415,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.3" version = "0.9.3"
@ -1291,6 +1300,7 @@ dependencies = [
name = "lua_macros" name = "lua_macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"convert_case",
"proc-macro2 1.0.64", "proc-macro2 1.0.64",
"quote 1.0.29", "quote 1.0.29",
"syn 2.0.25", "syn 2.0.25",

View File

@ -45,10 +45,14 @@
overlays = [(import rust-overlay)]; overlays = [(import rust-overlay)];
}; };
#rust-nightly = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default); nightly = true;
rust-stable = pkgs.rust-bin.stable.latest.default;
craneLib = (crane.mkLib pkgs).overrideToolchain rust-stable; rust =
if nightly
then pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default)
else pkgs.rust-bin.stable.latest.default;
craneLib = (crane.mkLib pkgs).overrideToolchain rust;
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
pkg-config pkg-config
@ -78,7 +82,7 @@
statix statix
ltex-ls ltex-ls
rust-stable rust
rust-analyzer rust-analyzer
cargo-edit cargo-edit
cargo-expand cargo-expand

View File

@ -1,11 +0,0 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::ToTokens;
// TODO: Do we need this noop?
pub fn generate_default_lua_function(input: &syn::Field) -> TokenStream2 {
let output: TokenStream2 = syn::parse(input.into_token_stream().into())
.expect("This is generated from valid rust code, it should stay that way.");
output
}

View File

@ -1,14 +1,12 @@
mod generate_noop_lua_function;
mod mark_as_ci_command;
mod struct_to_ci_enum; mod struct_to_ci_enum;
mod mark_as_ci_command;
use generate_noop_lua_function::generate_default_lua_function;
use mark_as_ci_command::generate_final_function; use mark_as_ci_command::generate_final_function;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::quote;
use struct_to_ci_enum::{generate_command_enum, generate_generate_ci_function}; use struct_to_ci_enum::{generate_command_enum, generate_generate_ci_function};
use syn::{self, ItemFn, Field, parse::Parser}; use syn::{self, ItemFn};
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn turn_struct_to_ci_commands(_attrs: TokenStream, input: TokenStream) -> TokenStream { pub fn turn_struct_to_ci_commands(_attrs: TokenStream, input: TokenStream) -> TokenStream {
@ -29,26 +27,6 @@ pub fn turn_struct_to_ci_commands(_attrs: TokenStream, input: TokenStream) -> To
.into() .into()
} }
/// Generate a default lua function implementation.
#[proc_macro_attribute]
pub fn gen_lua_function(_attrs: TokenStream, input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
//
let parser = Field::parse_named;
let input = parser.parse(input)
.expect("This is only defined for named fileds.");
// Build the trait implementation
let default_lua_function: TokenStream2 = generate_default_lua_function(&input);
quote! {
#default_lua_function
}
.into()
}
/// Turn a function into a valid ci command function /// Turn a function into a valid ci command function
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn ci_command(_attrs: TokenStream, input: TokenStream) -> TokenStream { pub fn ci_command(_attrs: TokenStream, input: TokenStream) -> TokenStream {

View File

@ -1,7 +1,12 @@
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::{Block, Expr, ExprBlock, GenericArgument, ReturnType, Stmt, Type}; use syn::{
braced,
punctuated::Punctuated,
token::{Comma, Semi},
Block, Expr, FnArg, Stmt, Token,
};
pub fn generate_final_function(input: &mut syn::ItemFn) -> TokenStream2 { pub fn generate_final_function(input: &mut syn::ItemFn) -> TokenStream2 {
append_tx_send_code(input); append_tx_send_code(input);
@ -24,137 +29,23 @@ fn append_tx_send_code(input: &mut syn::ItemFn) -> &mut syn::ItemFn {
.to_case(Case::Pascal) .to_case(Case::Pascal)
); );
let tx_send = match &input.sig.output { let tx_send = quote! {
syn::ReturnType::Default => { {
todo!( let tx = context.named_registry_value("sender_for_ci_commands");
"Does this case even trigger? All functions should have a output of (Result<$type, rlua::Error>)"
);
quote! {
{
let tx: std::sync::mpsc::Sender<crate::app::events::event_types::Event> =
context
.named_registry_value("sender_for_ci_commands")
.expect("This exists, it was set before");
tx tx
.send(Event::CommandEvent(Command::#function_name_pascal)) .send(Event::CommandEvent(Commands::#function_name_pascal))
.expect("This should work, as the reciever is not dropped"); .expect("This should work, as the reciever is not dropped");
}
}
}
syn::ReturnType::Type(_, ret_type) => {
let return_type = match *(ret_type.clone()) {
syn::Type::Path(path) => {
match path
.path
.segments
.first()
.expect("This is expected to be only one path segment")
.arguments
.to_owned()
{
syn::PathArguments::AngleBracketed(angled_path) => {
let angled_path = angled_path.args.to_owned();
let filtered_paths: Vec<_> = angled_path
.into_iter()
.filter(|generic_arg| {
if let GenericArgument::Type(generic_type) = generic_arg {
if let Type::Path(_) = generic_type {
true
} else {
false
}
} else {
false
}
})
.collect();
// There should only be two segments (the type is <String, rlua::Error>)
if filtered_paths.len() > 2 {
unreachable!(
"There should be no more than two filtered_output, but got: {:#?}",
filtered_paths
)
} else if filtered_paths.len() <= 0 {
unreachable!(
"There should be more than zero filtered_output, but got: {:#?}",
filtered_paths
)
}
if filtered_paths.len() == 2 {
// There is something else than rlua
let gen_type = if let GenericArgument::Type(ret_type) =
filtered_paths
.first()
.expect("One path segment should exists")
.to_owned()
{
ret_type
} else {
unreachable!("These were filtered above.");
};
let return_type_as_type_prepared = quote! {-> #gen_type};
let return_type_as_return_type: ReturnType = syn::parse(
return_type_as_type_prepared.to_token_stream().into(),
)
.expect("This is valid.");
return_type_as_return_type
} else {
// There is only rlua
ReturnType::Default
}
}
_ => unimplemented!("Only for angled paths"),
}
}
_ => unimplemented!("Only for path types"),
};
match return_type {
ReturnType::Default => {
quote! {
{
let tx: std::sync::mpsc::Sender<crate::app::events::event_types::Event> =
context
.named_registry_value("sender_for_ci_commands")
.expect("This exists, it was set before");
tx
.send(Event::CommandEvent(Command::#function_name_pascal))
.expect("This should work, as the reciever is not dropped");
}
}
}
ReturnType::Type(_, _) => {
quote! {
{
let tx: std::sync::mpsc::Sender<crate::app::events::event_types::Event> =
context
.named_registry_value("sender_for_ci_commands")
.expect("This exists, it was set before");
tx
.send(Event::CommandEvent(Command::#function_name_pascal(input_str)))
.expect("This should work, as the reciever is not dropped");
}
}
}
}
} }
}; };
let tx_send_block: Block = let content;
syn::parse(tx_send.into()).expect("This is a static string, it will always parse"); braced!(content in tx_send);
let tx_send_expr_block = ExprBlock { let mut tx_send_expr: Vec<Stmt> =
attrs: vec![], Block::parse_within(content).expect("This is a static string, it will always parse");
label: None,
block: tx_send_block,
};
let mut tx_send_stmt = vec![Stmt::Expr(Expr::Block(tx_send_expr_block), None)];
let mut new_stmts: Vec<Stmt> = Vec::with_capacity(input.block.stmts.len() + 1); let mut new_stmts: Vec<Stmt> = Vec::with_capacity(input.block.stmts.len() + tx_send_expr.len());
new_stmts.append(&mut tx_send_stmt); new_stmts.append(&mut tx_send_expr);
new_stmts.append(&mut input.block.stmts); new_stmts.append(&mut input.block.stmts);
input.block.stmts = new_stmts; input.block.stmts = new_stmts;
input input

View File

@ -4,81 +4,53 @@ use quote::{format_ident, quote};
use syn::{self, ReturnType}; use syn::{self, ReturnType};
pub fn generate_generate_ci_function(input: &syn::DeriveInput) -> TokenStream2 { pub fn generate_generate_ci_function(input: &syn::DeriveInput) -> TokenStream2 {
let mut functions_to_generate: Vec<TokenStream2> = vec![];
let input_tokens: TokenStream2 = match &input.data { let input_tokens: TokenStream2 = match &input.data {
syn::Data::Struct(input) => match &input.fields { syn::Data::Struct(input) => match &input.fields {
syn::Fields::Named(named_fields) => named_fields syn::Fields::Named(named_fields) => named_fields
.named .named
.iter() .iter()
.map(|field| -> TokenStream2 { .map(|field| -> TokenStream2 {
if field.attrs.iter().any(|attribute| { let field_ident = field.ident.as_ref().expect(
attribute.path() "These are only the named field, thus they all should have a name.",
== &syn::parse_str::<syn::Path>("gen_default_lua_function") );
.expect("This is valid rust code") let function_name_ident = format_ident!("fun_{}", field_ident);
}) { let function_name = format!("{}", field_ident);
let function_name = field quote! {
.ident let #function_name_ident = context.create_function(#field_ident).expect(
.as_ref() &format!(
.expect("These are only the named field, thus they all should have a name."); "The function: `{}` should be defined",
functions_to_generate.push(quote! { #function_name
#[ci_command] )
fn #function_name(context: Context, input_str: String) -> Result<(), rlua::Error> { );
Ok(())
} globals.set(#function_name, #function_name_ident).expect(
}); &format!(
generate_ci_part(field) "Setting a static global value ({}, fun_{}) should work",
} else { #function_name,
generate_ci_part(field) #function_name
)
);
} }
.into()
}) })
.collect(), .collect(),
_ => unimplemented!("Only implemented for named fileds"), _ => unimplemented!("Only implemented for named fileds"),
}, },
_ => unimplemented!("Only implemented for structs"), _ => unimplemented!("Only implemented for structs"),
}; };
let functions_to_generate: TokenStream2 = functions_to_generate.into_iter().collect();
let gen = quote! { let gen = quote! {
pub fn generate_ci_functions( pub fn generate_ci_functions(
context: &mut rlua::Context, context: &mut rlua::Context,
tx: std::sync::mpsc::Sender<crate::app::events::event_types::Event>) tx: std::sync::mpsc::Sender<crate::app::events::event_types::Event>)
{ {
context.set_named_registry_value("sender_for_ci_commands", tx).expect("This should always work, as the value is added before all else");
let globals = context.globals(); let globals = context.globals();
#input_tokens #input_tokens
} }
#functions_to_generate
}; };
gen.into() gen.into()
} }
fn generate_ci_part(field: &syn::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()
}
pub fn generate_command_enum(input: &syn::DeriveInput) -> TokenStream2 { pub fn generate_command_enum(input: &syn::DeriveInput) -> TokenStream2 {
let input_tokens: TokenStream2 = match &input.data { let input_tokens: TokenStream2 = match &input.data {
syn::Data::Struct(input) => match &input.fields { syn::Data::Struct(input) => match &input.fields {
@ -131,8 +103,7 @@ pub fn generate_command_enum(input: &syn::DeriveInput) -> TokenStream2 {
}; };
let gen = quote! { let gen = quote! {
#[derive(Debug)] pub enum Commands {
pub enum Command {
#input_tokens #input_tokens
} }
}; };

View File

@ -1,5 +1,4 @@
// FIXME: This file needs documentation with examples of how the proc macros work. use lua_macros::{turn_struct_to_ci_commands, ci_command};
use lua_macros::{ci_command, turn_struct_to_ci_commands};
use rlua::Context; use rlua::Context;
use super::events::event_types::Event; use super::events::event_types::Event;
@ -25,28 +24,24 @@ struct Commands<'lua> {
greet: fn(usize) -> String, greet: fn(usize) -> String,
// Closes the application // Closes the application
#[gen_default_lua_function]
exit: fn(), exit: fn(),
#[gen_default_lua_function] //command_line_show: fn(),
command_line_show: fn(), //command_line_hide: fn(),
#[gen_default_lua_function]
command_line_hide: fn(),
#[gen_default_lua_function] //cycle_planes: fn(),
cycle_planes: fn(), //cycle_planes_rev: fn(),
#[gen_default_lua_function]
cycle_planes_rev: fn(),
//// sends a message to the current room //// sends a message to the current room
room_message_send: fn(String) -> String, //room_message_send: fn(String),
} }
#[ci_command] #[ci_command]
fn greet(context: Context, input_str: String) -> Result<String, rlua::Error> { fn greet(_context: Context, name: String) -> Result<String, rlua::Error> {
Ok(format!("Name is {}", input_str)) Ok(format!("Name is {}", name))
} }
#[ci_command] #[ci_command]
fn room_message_send(context: Context, input_str: String) -> Result<String, rlua::Error> { fn exit(_context: Context, _input_str: String) -> Result<(), rlua::Error> {
Ok(format!("Sent message: {}", input_str)) Event::CommandEvent(Commands::Exit);
Ok(())
} }

View File

@ -1,11 +1,15 @@
use anyhow::Result; use anyhow::{bail, Context, Result};
use cli_log::info; use cli_log::warn;
use crate::app::{events::event_types::EventStatus, App}; use crate::app::{events::event_types::EventStatus, App};
pub async fn handle(app: &mut App<'_>, output: &String) -> Result<EventStatus> { pub async fn handle(app: &mut App<'_>, output: String) -> Result<EventStatus> {
info!("Recieved command output: `{}`", output); info!("Recieved command output: `{}`");
app.ui.set_command_output(output); if let Some(cli) = app.ui.cli {
cli.
} else {
warn!("There is no way to display the output!");
}
Ok(EventStatus::Ok) Ok(EventStatus::Ok)
} }

View File

@ -1,36 +1,34 @@
use crate::app::{events::event_types::EventStatus, App, command_interface::Command}; use crate::app::{command::Command, events::event_types::EventStatus, App};
use anyhow::Result; use anyhow::Result;
use cli_log::info; use cli_log::info;
pub async fn handle(app: &mut App<'_>, command: &Command) -> Result<EventStatus> { pub async fn handle(app: &mut App<'_>, command: &Command) -> Result<EventStatus> {
info!("Handling command: {:#?}", command); info!("Handling command: {:#?}", command);
Ok(match command { match command {
Command::Exit => EventStatus::Terminate, Command::Exit => return Ok(EventStatus::Terminate),
Command::CommandLineShow => { Command::CommandLineShow => {
app.ui.cli_enable(); app.ui.cli_enable();
EventStatus::Ok
} }
Command::CommandLineHide => { Command::CommandLineHide => {
app.ui.cli_disable(); app.ui.cli_disable();
EventStatus::Ok
} }
Command::CyclePlanes => { Command::CyclePlanes => {
app.ui.cycle_main_input_position(); app.ui.cycle_main_input_position();
EventStatus::Ok
} }
Command::CyclePlanesRev => { Command::CyclePlanesRev => {
app.ui.cycle_main_input_position_rev(); app.ui.cycle_main_input_position_rev();
EventStatus::Ok
} }
Command::RoomMessageSend(msg) => { Command::RoomMessageSend(msg) => {
if let Some(room) = app.status.room_mut() { if let Some(room) = app.status.room_mut() {
room.send(msg.clone()).await?; room.send(msg.clone()).await?;
} else {
// FIXME: This needs a callback to return an error.
} }
EventStatus::Ok
} }
}) }
Ok(EventStatus::Ok)
} }

View File

@ -2,11 +2,7 @@ use anyhow::Result;
use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyEvent, KeyModifiers};
use crate::{ use crate::{
app::{ app::{events::event_types::EventStatus, App},
command_interface::Command,
events::event_types::{Event, EventStatus},
App,
},
ui::central, ui::central,
}; };
@ -15,33 +11,25 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
CrosstermEvent::Key(KeyEvent { CrosstermEvent::Key(KeyEvent {
code: KeyCode::Esc, .. code: KeyCode::Esc, ..
}) => { }) => {
app.transmitter app.transmitter.send(Event::CommandEvent(Command::Exit)).await?;
.send(Event::CommandEvent(Command::Exit))
.await?;
} }
CrosstermEvent::Key(KeyEvent { CrosstermEvent::Key(KeyEvent {
code: KeyCode::Tab, .. code: KeyCode::Tab, ..
}) => { }) => {
app.transmitter command::execute(app.channel_tx(), Command::CyclePlanes).await?;
.send(Event::CommandEvent(Command::CyclePlanes))
.await?;
} }
CrosstermEvent::Key(KeyEvent { CrosstermEvent::Key(KeyEvent {
code: KeyCode::BackTab, code: KeyCode::BackTab,
.. ..
}) => { }) => {
app.transmitter command::execute(app.channel_tx(), Command::CyclePlanesRev).await?;
.send(Event::CommandEvent(Command::CyclePlanesRev))
.await?;
} }
CrosstermEvent::Key(KeyEvent { CrosstermEvent::Key(KeyEvent {
code: KeyCode::Char('c'), code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL, modifiers: KeyModifiers::CONTROL,
.. ..
}) => { }) => {
app.transmitter command::execute(app.channel_tx(), Command::CommandLineShow).await?;
.send(Event::CommandEvent(Command::CommandLineShow))
.await?;
} }
input => match app.ui.input_position() { input => match app.ui.input_position() {
central::InputPosition::MessageCompose => { central::InputPosition::MessageCompose => {
@ -51,11 +39,11 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
modifiers: KeyModifiers::ALT, modifiers: KeyModifiers::ALT,
.. ..
}) => { }) => {
app.transmitter command::execute(
.send(Event::CommandEvent(Command::RoomMessageSend( app.channel_tx(),
app.ui.message_compose.lines().join("\n"), Command::RoomMessageSend(app.ui.message_compose.lines().join("\n")),
))) )
.await?; .await?;
app.ui.message_compose_clear(); app.ui.message_compose_clear();
} }
_ => { _ => {
@ -165,7 +153,7 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
"There can only be one line in the buffer, as we collect it on enter being inputted" "There can only be one line in the buffer, as we collect it on enter being inputted"
) )
.to_owned(); .to_owned();
let output = app.handle_ci_event(&cli_event).await?; let output = (&cli_event).await?;
// delete the old text: // delete the old text:

View File

@ -1,4 +1,6 @@
pub mod command; pub mod command;
pub mod lua_command;
pub mod main; pub mod main;
pub mod matrix; pub mod matrix;
pub mod setup; pub mod setup;
pub mod ci_output;

View File

@ -3,9 +3,9 @@ mod handlers;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use crossterm::event::Event as CrosstermEvent; use crossterm::event::Event as CrosstermEvent;
use crate::app::{status::State, App, command_interface::Command}; use crate::app::{command::Command, status::State, App};
use self::handlers::{command, main, matrix, setup}; use self::handlers::{command, lua_command, main, matrix, setup};
use super::EventStatus; use super::EventStatus;
@ -14,11 +14,21 @@ pub enum Event {
InputEvent(CrosstermEvent), InputEvent(CrosstermEvent),
MatrixEvent(matrix_sdk::deserialized_responses::SyncResponse), MatrixEvent(matrix_sdk::deserialized_responses::SyncResponse),
CommandEvent(Command), CommandEvent(Command),
LuaCommand(String),
CiOutput(String),
} }
impl Event { impl Event {
pub async fn handle(&self, app: &mut App<'_>) -> Result<EventStatus> { pub async fn handle(&self, app: &mut App<'_>) -> Result<EventStatus> {
match &self { match &self {
Event::LuaCommand(command) => lua_command::handle(app, command)
.await
.with_context(|| format!("Failed to handle lua command: `{:#?}`", command)),
Event::CiOutput(output) => ci_output::handle(app, output)
.await
.with_context(|| format!("Failed to handle ci output: `{:#?}`", output)),
Event::MatrixEvent(event) => matrix::handle(app, event) Event::MatrixEvent(event) => matrix::handle(app, event)
.await .await
.with_context(|| format!("Failed to handle matrix event: `{:#?}`", event)), .with_context(|| format!("Failed to handle matrix event: `{:#?}`", event)),

View File

@ -1,6 +1,11 @@
#[derive(Debug)] #[derive(Debug)]
pub enum EventStatus { pub enum EventStatus {
/// The event was handled successfully
Ok, Ok,
/// TODO
Finished, Finished,
/// Terminate the whole application
Terminate, Terminate,
} }

View File

@ -3,13 +3,14 @@ pub mod events;
pub mod status; pub mod status;
pub mod transmitter; pub mod transmitter;
use std::{path::Path, sync::mpsc::Sender as StdSender}; use std::path::Path;
use anyhow::{Context, Error, Result}; use anyhow::{Context, Error, Result};
use cli_log::info; use cli_log::info;
use matrix_sdk::Client; use matrix_sdk::Client;
use rlua::Lua; use rlua::Lua;
use status::{State, Status}; use status::{State, Status};
use tokio::sync::mpsc::Sender;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use crate::{ use crate::{
@ -34,7 +35,7 @@ pub struct App<'ui> {
impl App<'_> { impl App<'_> {
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
fn set_up_lua(tx: StdSender<Event>) -> Lua { fn set_up_lua(tx: Sender<Event>) -> Lua {
let lua = Lua::new(); let lua = Lua::new();
lua.context(|mut lua_context| { lua.context(|mut lua_context| {
@ -61,25 +62,10 @@ impl App<'_> {
input_listener_killer: CancellationToken::new(), input_listener_killer: CancellationToken::new(),
matrix_listener_killer: CancellationToken::new(), matrix_listener_killer: CancellationToken::new(),
lua: set_up_lua(transmitter.std_tx()), lua: set_up_lua(transmitter.tx()),
}) })
} }
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(
@ -107,8 +93,8 @@ impl App<'_> {
match event.handle(self).await? { match event.handle(self).await? {
event_types::EventStatus::Ok => (), event_types::EventStatus::Ok => (),
event_types::EventStatus::Finished => (),
event_types::EventStatus::Terminate => break, event_types::EventStatus::Terminate => break,
_ => (),
}; };
} }

View File

@ -1,5 +1,5 @@
use anyhow::{Error, Result}; use anyhow::{Error, Result};
use cli_log::{warn, info}; use cli_log::{info, warn};
use indexmap::IndexMap; use indexmap::IndexMap;
use matrix_sdk::{ use matrix_sdk::{
room::MessagesOptions, room::MessagesOptions,
@ -62,7 +62,7 @@ impl Room {
let events = self.matrix_room.messages(messages_options).await?; let events = self.matrix_room.messages(messages_options).await?;
self.timeline_end = events.end; self.timeline_end = events.end;
for event in events.chunk.iter() { for event in events.chunk {
self.timeline.insert( self.timeline.insert(
0, 0,
match event.event.deserialize() { match event.event.deserialize() {

View File

@ -1,5 +1,3 @@
use std::sync::mpsc as StdMpsc;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use tokio::sync::mpsc; use tokio::sync::mpsc;
@ -8,29 +6,17 @@ use super::events::event_types::Event;
pub struct Transmitter { pub struct Transmitter {
tx: mpsc::Sender<Event>, tx: mpsc::Sender<Event>,
rx: mpsc::Receiver<Event>, rx: mpsc::Receiver<Event>,
std_tx: StdMpsc::Sender<Event>,
std_rx: StdMpsc::Receiver<Event>,
} }
impl Transmitter { impl Transmitter {
pub fn new() -> Transmitter { pub fn new() -> Transmitter {
let (std_tx, std_rx) = StdMpsc::channel();
let (tx, rx) = mpsc::channel(256); let (tx, rx) = mpsc::channel(256);
Transmitter { Transmitter { tx, rx }
tx,
rx,
std_tx,
std_rx,
}
} }
pub fn tx(&self) -> mpsc::Sender<Event> { pub fn tx(&self) -> mpsc::Sender<Event> {
self.tx.to_owned() self.tx.to_owned()
} }
pub fn std_tx(&self) -> StdMpsc::Sender<Event> {
self.std_tx.to_owned()
}
pub async fn recv(&mut self) -> Result<Event> { pub async fn recv(&mut self) -> Result<Event> {
match self.rx.recv().await { match self.rx.recv().await {
Some(event) => Ok(event), Some(event) => Ok(event),