diff --git a/src/app/command_interface/command_list/api.tri b/src/app/command_interface/command_list/api.tri new file mode 100644 index 0000000..8d7f6de --- /dev/null +++ b/src/app/command_interface/command_list/api.tri @@ -0,0 +1,142 @@ +/* +* Copyright (C) 2023 - 2024: +* The Trinitrix Project +* SPDX-License-Identifier: LGPL-3.0-or-later +* +* This file is part of the Trixy crate for Trinitrix. +* +* Trixy is free software: you can redistribute it and/or modify +* it under the terms of the Lesser GNU General Public License as +* published by the Free Software Foundation, either version 3 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* and the Lesser GNU General Public License along with this program. +* If not, see . +*/ + +//// Prints to the output, with a newline. +// HACK(@soispha): The stdlib Lua `print()` function has stdout as output hardcoded, +// redirecting stdout seems too much like a hack thus we are just redefining the print function +// to output to a controlled output. <2023-09-09> +// This is implemented only for lua +/* fn print(CommandTransferValue); */ + +mod trinitrix { + /// Language specific functions, which mirror the `trinitrix.api` namespace. + /// That is, if you have to choose between a `std` and a `api` function choose the `std` + /// one as it will most likely be more high-level and easier to use (as it isn't abstracted + /// over multiple languages). Feel free to drop down to the lower level api, if you feel + /// like that more, it should be as stable and user-oriented as the `std` functions + mod stdi {} + + /// General API to change stuff in Trinitrix + mod api { + /// Closes the application + fn exit(); + + /// Send a message to the current room + /// The send message is interpreted literally. + fn room_message_send(message: String); + + //// Open the help pages at the first occurrence of + //// the input string if it is Some, otherwise open + //// the help pages at the start + // TODO(@soispha): To be implemented <2024-03-09> + // fn help(Option); + + //// Register a function to be used with the Trinitrix api + // (This function is not actually implemented here) + /* declare register_function: false, */ + + /// Function that change the UI, or UI state + mod ui { + enum Mode { + /// Default mode (navigation mode) + Normal, + /// Allows you to insert things + Insert, + /// actives the command line + Command, + } + + /// Change the active mode + fn set_mode(mode: Mode); + + /// Go to the next plane + fn cycle_planes(); + /// Go to the previous plane + fn cycle_planes_rev(); + } + + /// Manipulate keymappings, the mode is specified as a String build up of all mode + /// the keymapping should be active in. The mapping works as follows: + /// n => normal Mode + /// c => command Mode + /// i => insert Mode + /// + /// The key works in a similar matter, specifying the required keypresses to trigger the + /// callback. For example "aba" for require the user to press "a" then "b" then "a" again + /// to trigger the mapping. Special characters are encoded as follows: + /// "ba" => "Ctrl+a" then "b" then "a" + /// "" => "A" or "Shift+a" + /// "A" => "A" + /// " " => "Alt+a" () or "Meta+a"() (most terminals can't really differentiate between these characters) + /// "a" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super) + /// "" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter) + /// "a " => "a" then a literal space (" ") + /// "å🙂" => "å" then "🙂" (full Unicode support!) + /// "" => escape key + /// "" => F3 key + /// "" => backspace key (and so forth) + /// "" => a literal "-" + /// "" or "" => a literal "<" + /// "" or "" => a literal ">" + /// + /// The callback MUST be registered first by calling + /// `trinitrix.api.register_function()` the returned value can than be used to + /// set the keymap. + mod keymaps { + /// Add a new keymapping + fn add(mode: String, key: String, callback: fn()); + + /// Remove a keymapping + /// + /// Does nothing, if the keymapping doesn't exists yet + fn remove(mode: String, key: String); + + /// List declared keymappings + fn get(mode: String); + } + + /// Functions only used internally within Trinitrix + mod raw { + /// Send an error to the default error output + fn raise_error(error_message: String); + + /// Send output to the default output + /// This is mainly used to display the final + /// output of evaluated lua commands. + fn display_output(output_message: String); + + /// Input a character without checking for possible keymaps + /// If the current state does not expect input, this character is ignored + /// The encoding is the same as in the `trinitrix.api.keymaps` commands + fn send_input_unprocessed(input: String); + + /// This namespace is used to store some command specific data (like functions, as + /// ensuring memory locations stay allocated in garbage collected language is hard) + /// + /// Treat it as an implementation detail + mod __private {} + } + } +} + +// Trixy is sort of a subset of rust +// vim: syntax=rust diff --git a/src/app/command_interface/command_list/mod.rs b/src/app/command_interface/command_list/mod.rs index 9826c58..6906c46 100644 --- a/src/app/command_interface/command_list/mod.rs +++ b/src/app/command_interface/command_list/mod.rs @@ -1,150 +1,14 @@ -// Use `cargo expand app::command_interface::command_list` for an overview of the file contents +// Run the `api` bin to see the generated api -use language_macros::parse_command_enum; +use crate::app::{events::Event, COMMAND_TRANSMITTER}; -// TODO(@soispha): Should these paths be moved to the proc macro? -// As they are not static, it could be easier for other people, -// if they stay here. -use crate::app::command_interface::command_transfer_value::{ - support_types::Function, CommandTransferValue, -}; -use crate::app::Event; -use mlua::IntoLua; +include!(concat!(env!("OUT_DIR"), "/api.rs")); -parse_command_enum! { -commands { - /// Prints to the output, with a newline. - // HACK(@soispha): The stdlib Lua `print()` function has stdout as output hardcoded, - // redirecting stdout seems too much like a hack thus we are just redefining the print function - // to output to a controlled output. <2023-09-09> - declare print: fn(CommandTransferValue), +pub fn handle_cmd(cmd: Commands) { + let tx = COMMAND_TRANSMITTER + .get() + .expect("The cell should always be populated, at this point"); - namespace trinitrix { - /// Language specific functions, which mirror the `trinitrix.api` namespace. - /// That is, if you have to choose between a `std` and a `api` function choose the `std` - /// one as it will most likely be more high-level and easier to use (as it isn't abstracted - /// over multiple languages). Feel free to drop down to the lower level api, if you feel - /// like that more, it should be as stable and user-oriented as the `std` functions - namespace std { - /// This command is a no-op, it's just here to ensure that the 'std' - /// namespace get actually created - // FIXME(@soispha): Add an attribute to namespaces to avoid having to use - // empty functions <2023-10-14> - declare private_initializer_std: fn(), - }, - - /// Debug only functions, these are effectively useless - namespace debug { - /// Greets the user - declare greet: fn(String) -> String, - - /// Returns a table of greeted users - declare greet_multiple: fn() -> Table, - }, - - /// General API to change stuff in Name - namespace api { - /// Closes the application - declare exit: fn(), - /// Send a message to the current room - /// The send message is interpreted literally. - declare room_message_send: fn(String), - /// Open the help pages at the first occurrence of - /// the input string if it is Some, otherwise open - /// the help pages at the start - declare help: fn(Option), - - // Register a function to be used with the Trinitrix api - // (This function is not actually implemented here) - /* declare register_function: false, */ - - /// Function that change the UI, or UI state - namespace ui { - /// Shows the command line - declare command_line_show: fn(), - - /// Hides the command line - declare command_line_hide: fn(), - - /// Go to the next plane - declare cycle_planes: fn(), - /// Go to the previous plane - declare cycle_planes_rev: fn(), - - /// Sets the current app mode to Normal / navigation mode - declare set_mode_normal: fn(), - /// Sets the current app mode to Insert / editing mode - declare set_mode_insert: fn(), - }, - - /// Manipulate keymappings, the mode is specified as a String build up of all mode - /// the keymapping should be active in. The mapping works as follows: - /// n => normal Mode - /// c => command Mode - /// i => insert Mode - /// - /// The key works in a similar matter, specifying the required keypresses to trigger the - /// callback. For example "aba" for require the user to press "a" then "b" then "a" again - /// to trigger the mapping. Special characters are encoded as follows: - /// "ba" => "Ctrl+a" then "b" then "a" - /// "" => "A" or "Shift+a" - /// "A" => "A" - /// " " => "Alt+a" () or "Meta+a"() (most terminals can't really differentiate between these characters) - /// "a" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super) - /// "" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter) - /// "a " => "a" then a literal space (" ") - /// "å🙂" => "å" then "🙂" (full Unicode support!) - /// "" => escape key - /// "" => F3 key - /// "" => backspace key (and so forth) - /// "" => a literal "-" - /// "" or "" => a literal "<" - /// "" or "" => a literal ">" - /// - /// The callback MUST be registered first by calling - /// `trinitrix.api.register_function()` the returned value can than be used to - /// set the keymap. - namespace keymaps { - /// Add a new keymapping - declare add: fn((/* mode: */ String, /* key: */ String, /* callback: */ Function)), - - /// Remove a keymapping - /// - /// Does nothing, if the keymapping doesn't exists - declare remove: fn((/* mode: */ String, /* key: */ String)), - - /// List declared keymappings - declare get: fn(/* mode: */ String), - }, - - /// Functions only used internally within Trinitrix - namespace raw { - /// Send an error to the default error output - declare raise_error: fn(String), - - /// Send output to the default output - /// This is mainly used to display the final - /// output of evaluated lua commands. - declare display_output: fn(String), - - /// Input a character without checking for possible keymaps - /// If the current state does not expect input, this character is ignored - /// The encoding is the same as in the `trinitrix.api.keymaps` commands - declare send_input_unprocessed: fn(String), - - /// This namespace is used to store some command specific data (like functions, as - /// ensuring memory locations stay allocated in garbage collected language is hard) - /// - /// Treat it as an implementation detail - namespace __private { - /// This command is a no-op, it's just here to ensure that the '__private' - /// namespace get actually created - // FIXME(@soispha): Add an attribute to namespaces to avoid having to use - // empty functions <2023-10-14> - declare private_initializer_private: fn(), - }, - }, - }, - }, -} + // FIXME: The None here is definitely wrong <2024-05-03> + tx.send(Event::CommandEvent(cmd, None)); } diff --git a/src/app/command_interface/mod.rs b/src/app/command_interface/mod.rs index c2bc7c8..29c8b8f 100644 --- a/src/app/command_interface/mod.rs +++ b/src/app/command_interface/mod.rs @@ -1,5 +1,5 @@ pub mod command_list; -pub mod command_transfer_value; -pub mod lua_command_manager; +// pub mod command_transfer_value; +// pub mod lua_command_manager; pub use command_list::*; diff --git a/src/app/events/handlers/command.rs b/src/app/events/handlers/command.rs index d39d89d..87e7e8d 100644 --- a/src/app/events/handlers/command.rs +++ b/src/app/events/handlers/command.rs @@ -1,31 +1,36 @@ -use std::{collections::HashMap, str::FromStr}; +use std::{mem, str::FromStr}; -use anyhow::{Error, Result}; +use crate::{ + app::{ + command_interface::{ + trinitrix::{ + api::{keymaps::Keymaps, raw::Raw, ui::Ui, Api}, + Trinitrix, + }, + Commands, + }, + events::EventStatus, + status::State, + App, + }, + trinitrix::api::ui::Mode, + ui::central::InputPosition, +}; +use anyhow::Result; use cli_log::{info, trace, warn}; use crossterm::event::Event; use keymaps::{ key_repr::{Key, Keys}, trie::Node, }; -use tokio::sync::oneshot; - -use crate::{ - app::{ - command_interface::{ - command_transfer_value::{CommandTransferValue, Table}, - Api, Command, Debug, Keymaps, Raw, Trinitrix, Ui, - }, - events::EventStatus, - status::State, - App, - }, - ui::central::InputPosition, -}; +use trixy::oneshot; pub async fn handle( app: &mut App<'_>, - command: &Command, - output_callback: Option>, + command: &Commands, + + // FIXME(@soispha): The `String` is temporary <2024-05-03> + output_callback: Option>, ) -> Result { // A command can both return _status output_ (what you would normally print to stderr) // and _main output_ (the output which is normally printed to stdout). @@ -51,110 +56,90 @@ pub async fn handle( app.status.add_error_message(format!($str, $($args),+)) }; } - macro_rules! send_main_output { - ($str:expr) => { - if let Some(sender) = output_callback { - sender - .send(CommandTransferValue::from($str)) - .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?; - } - }; - ($str:expr, $($args:ident),+) => { - if let Some(sender) = output_callback { - sender - .send(CommandTransferValue::from(format!($str, $($args),+))) - .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?; - } - }; - } + // macro_rules! send_main_output { + // ($str:expr) => { + // if let Some(sender) = output_callback { + // sender + // .send(CommandTransferValue::from($str)) + // .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?; + // } + // }; + // ($str:expr, $($args:ident),+) => { + // if let Some(sender) = output_callback { + // sender + // .send(CommandTransferValue::from(format!($str, $($args),+))) + // .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?; + // } + // }; + // } trace!("Handling command: {:#?}", command); Ok(match command { - Command::Print(output) => { - let output_str: String = output.to_string(); - send_status_output!(output_str); - EventStatus::Ok - } - - Command::Trinitrix(trinitrix) => match trinitrix { - Trinitrix::Debug(debug) => match debug { - Debug::Greet(msg) => { - send_main_output!("Greeting, {}!", msg); - EventStatus::Ok - } - Debug::GreetMultiple => { - let mut table: Table = HashMap::new(); - table.insert("UserId".to_owned(), CommandTransferValue::Integer(2)); - table.insert( - "UserName".to_owned(), - CommandTransferValue::String("James".to_owned()), - ); - - let mut second_table: Table = HashMap::new(); - second_table.insert("interface".to_owned(), CommandTransferValue::Integer(3)); - second_table.insert("api".to_owned(), CommandTransferValue::Boolean(true)); - table.insert( - "Versions".to_owned(), - CommandTransferValue::Table(second_table), - ); - send_main_output!(table); - EventStatus::Ok - } - }, + Commands::Trinitrix(trinitrix) => match trinitrix { + Trinitrix::Stdi(_) => { + // No-op I guess + EventStatus::Ok + } Trinitrix::Api(api) => match api { - Api::Exit => { + Api::exit => { send_status_output!("Terminating the application.."); EventStatus::Terminate } - Api::RoomMessageSend(msg) => { + Api::room_message_send { message } => { if let Some(room) = app.status.room_mut() { - room.send(msg.clone()).await?; - send_status_output!("Sent message: `{}`", msg); + room.send(message.clone()).await?; + send_status_output!("Sent message: `{}`", message); } else { // FIXME(@soispha): This should raise an error within lua, as it would // otherwise be very confusing <2023-09-20> - warn!("Can't send message: `{}`, as there is no open room!", &msg); + warn!( + "Can't send message: `{}`, as there is no open room!", + &message + ); } + + // NOTE(@soispha): This is temporary, until trixy can do it automatically <2024-05-03> + mem::forget(message); EventStatus::Ok } - Api::Help(_) => todo!(), Api::Ui(ui) => match ui { - Ui::CommandLineShow => { - app.ui.cli_enable(); - app.status.set_state(State::Command); - send_status_output!("CLI online"); - EventStatus::Ok - } - Ui::CommandLineHide => { - app.ui.cli_disable(); - send_status_output!("CLI offline"); - EventStatus::Ok - } - Ui::CyclePlanes => { + Ui::set_mode { mode } => match mode { + Mode::Normal => { + app.status.set_state(State::Normal); + send_status_output!("Set input mode to Normal"); + EventStatus::Ok + } + Mode::Insert => { + app.status.set_state(State::Insert); + app.ui.set_input_position(InputPosition::MessageCompose); + send_status_output!("Set input mode to Insert"); + EventStatus::Ok + } + Mode::Command => { + app.ui.cli_enable(); + app.status.set_state(State::Command); + send_status_output!("Set input mode to CLI"); + EventStatus::Ok + } + }, + Ui::cycle_planes => { app.ui.cycle_main_input_position(); send_status_output!("Switched main input position"); EventStatus::Ok } - Ui::CyclePlanesRev => { + Ui::cycle_planes_rev => { app.ui.cycle_main_input_position_rev(); send_status_output!("Switched main input position; reversed"); EventStatus::Ok } - Ui::SetModeNormal => { - app.status.set_state(State::Normal); - send_status_output!("Set input mode to Normal"); - EventStatus::Ok - } - Ui::SetModeInsert => { - app.status.set_state(State::Insert); - app.ui.set_input_position(InputPosition::MessageCompose); - send_status_output!("Set input mode to Insert"); - EventStatus::Ok - } }, Api::Keymaps(keymaps) => match keymaps { - Keymaps::Add((mode, key, callback)) => { + Keymaps::add { + mode, + key, + callback, + } => { mode.chars().for_each(|char| { info!("Setting keymaping ('{}') for mode '{}'", key, char); let parsed_keys = key @@ -179,7 +164,7 @@ pub async fn handle( } trie.insert(&parsed_keys, callback.to_owned()) .map_err(|err| { - send_error_output!(err.to_string()); + send_error_output!(format!("{:#?}", err)); }) .expect("We already dealt with the error") } @@ -187,60 +172,140 @@ pub async fn handle( }; }); + mem::forget(key); + mem::forget(mode); EventStatus::Ok } - // TODO(@soispha): Well.., we should probably add these functions: <2023-10-15> - Keymaps::Remove((mode, key)) => todo!(), - Keymaps::Get(mode) => todo!(), + // FIXME(@soispha): It would be nice to have these functions, but well.. + // someone needs to write them <2024-05-03> + Keymaps::remove { mode, key } => todo!(), + Keymaps::get { mode } => todo!(), }, Api::Raw(raw) => match raw { - Raw::RaiseError(err) => { - send_error_output!(err); + Raw::raise_error { error_message } => { + send_error_output!(error_message); + mem::forget(error_message); EventStatus::Ok } - Raw::DisplayOutput(output) => { + Raw::display_output { output_message } => { // TODO(@Soispha): This is only used to show the Lua command output to the user. // Lua commands already receive the output. This should probably be communicated // better, should it? - send_status_output!(output); + send_status_output!(output_message); + mem::forget(output_message); EventStatus::Ok } - Raw::Private(_) => { - // no-op, read the comment about it in the `command_list` + Raw::send_input_unprocessed { input } => { + let output = match app.status.state() { + State::Insert => { + let key = Key::from_str(&input)?; + let cross_input: Event = key.try_into()?; + app.ui + .message_compose + .input(tui_textarea::Input::from(cross_input)); + EventStatus::Ok + } + State::Command => { + let key = Key::from_str(&input)?; + let cross_input: Event = key.try_into()?; + app.ui + .cli + .as_mut() + .expect("This should exist, when the state is 'Command'") + .input(tui_textarea::Input::from(cross_input)); + EventStatus::Ok + } + State::Normal + | State::Setup + | State::KeyInputPending { + old_state: _, + pending_keys: _, + } => EventStatus::Ok, + }; + mem::forget(input); + output + } + Raw::Private(private) => { + // no-op, this was used to store functions (not so sure, if we need it + // any longer) EventStatus::Ok } - Raw::SendInputUnprocessed(char) => match app.status.state() { - State::Insert => { - let key = Key::from_str(char)?; - let cross_input: Event = key.try_into()?; - app.ui - .message_compose - .input(tui_textarea::Input::from(cross_input)); - EventStatus::Ok - } - State::Command => { - let key = Key::from_str(char)?; - let cross_input: Event = key.try_into()?; - app.ui - .cli - .as_mut() - .expect("This should exist, when the state is 'Command'") - .input(tui_textarea::Input::from(cross_input)); - EventStatus::Ok - } - State::Normal - | State::Setup - | State::KeyInputPending { - old_state: _, - pending_keys: _, - } => EventStatus::Ok, - }, }, }, - Trinitrix::Std(_) => { - // no-op, read the comment about it in the `command_list` - EventStatus::Ok - } }, + // Command::Print(output) => { + // let output_str: String = output.to_string(); + // send_status_output!(output_str); + // EventStatus::Ok + // } + // + // Command::Trinitrix(trinitrix) => match trinitrix { + // Trinitrix::Debug(debug) => match debug { + // Debug::Greet(msg) => { + // send_main_output!("Greeting, {}!", msg); + // EventStatus::Ok + // } + // Debug::GreetMultiple => { + // let mut table: Table = HashMap::new(); + // table.insert("UserId".to_owned(), CommandTransferValue::Integer(2)); + // table.insert( + // "UserName".to_owned(), + // CommandTransferValue::String("James".to_owned()), + // ); + // + // let mut second_table: Table = HashMap::new(); + // second_table.insert("interface".to_owned(), CommandTransferValue::Integer(3)); + // second_table.insert("api".to_owned(), CommandTransferValue::Boolean(true)); + // table.insert( + // "Versions".to_owned(), + // CommandTransferValue::Table(second_table), + // ); + // send_main_output!(table); + // EventStatus::Ok + // } + // }, + // Trinitrix::Api(api) => match api { + // Api::RoomMessageSend(msg) => { + // } + // Api::Help(_) => todo!(), + // Api::Ui(ui) => match ui { + // Ui::CommandLineShow => { + // } + // Ui::CommandLineHide => { + // app.ui.cli_disable(); + // send_status_output!("CLI offline"); + // EventStatus::Ok + // } + // Ui::CyclePlanes => { + // } + // Ui::CyclePlanesRev => { + // } + // Ui::SetModeNormal => { + // } + // Ui::SetModeInsert => { + // } + // }, + // Api::Keymaps(keymaps) => match keymaps { + // Keymaps::Add((mode, key, callback)) => { + // } + // // TODO(@soispha): Well.., we should probably add these functions: <2023-10-15> + // Keymaps::Remove((mode, key)) => todo!(), + // Keymaps::Get(mode) => todo!(), + // }, + // Api::Raw(raw) => match raw { + // Raw::RaiseError(err) => { + // } + // Raw::DisplayOutput(output) => { + // } + // Raw::Private(_) => { + // } + // Raw::SendInputUnprocessed(char) => + // }, + // }, + // Trinitrix::Std(_) => { + // // no-op, read the comment about it in the `command_list` + // EventStatus::Ok + // } + // }, }) } diff --git a/src/app/events/handlers/function.rs b/src/app/events/handlers/function.rs index ce431f8..1ce4518 100644 --- a/src/app/events/handlers/function.rs +++ b/src/app/events/handlers/function.rs @@ -1,13 +1,13 @@ -use anyhow::Result; - -use crate::app::{ - command_interface::command_transfer_value::support_types::Function, events::EventStatus, App, -}; - -// TODO(@soispha): We just assume for now that all functions originate in lua. This module will in -// future versions house check for the language the function came from <2023-10-15> -pub async fn handle(app: &mut App<'_>, function: Function) -> Result { - app.lua.execute_function(function).await; - - Ok(EventStatus::Ok) -} +// use anyhow::Result; +// +// use crate::app::{ +// command_interface::command_transfer_value::support_types::Function, events::EventStatus, App, +// }; +// +// // TODO(@soispha): We just assume for now that all functions originate in lua. This module will in +// // future versions house check for the language the function came from <2023-10-15> +// pub async fn handle(app: &mut App<'_>, function: Function) -> Result { +// app.lua.execute_function(function).await; +// +// Ok(EventStatus::Ok) +// } diff --git a/src/app/events/handlers/input.rs b/src/app/events/handlers/input.rs index 250d6d9..77d15fa 100644 --- a/src/app/events/handlers/input.rs +++ b/src/app/events/handlers/input.rs @@ -4,7 +4,13 @@ use crossterm::event::Event as CrosstermEvent; use keymaps::key_repr::{Key, Keys}; use crate::app::{ - command_interface::{Api::Raw, Command, Raw::SendInputUnprocessed, Trinitrix::Api}, + command_interface::{ + trinitrix::{ + api::{raw::Raw, Api}, + Trinitrix, + }, + Commands, + }, events::{Event, EventStatus}, status::State, App, @@ -24,7 +30,11 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result, input_event: &CrosstermEvent) -> Result, input_event: &CrosstermEvent) -> Result, command: String) -> Result { - trace!("Recieved ci command: `{command}`; executing.."); - - app.lua.execute_code(command).await; - - Ok(EventStatus::Ok) -} +// use anyhow::Result; +// use cli_log::trace; +// +// use crate::app::{events::EventStatus, App}; +// +// // This function is here mainly to reserve this spot for further processing of the lua command. +// // TODO(@Soispha): Move the lua executor thread code from app to this module +// pub async fn handle(app: &mut App<'_>, command: String) -> Result { +// trace!("Recieved ci command: `{command}`; executing.."); +// +// app.lua.execute_code(command).await; +// +// Ok(EventStatus::Ok) +// } diff --git a/src/app/events/handlers/mod.rs b/src/app/events/handlers/mod.rs index dd58e16..4a9b144 100644 --- a/src/app/events/handlers/mod.rs +++ b/src/app/events/handlers/mod.rs @@ -8,4 +8,4 @@ pub mod matrix; // ci pub mod command; pub mod lua_command; -pub mod function; +// pub mod function; diff --git a/src/app/events/mod.rs b/src/app/events/mod.rs index a878497..c1b17c2 100644 --- a/src/app/events/mod.rs +++ b/src/app/events/mod.rs @@ -3,26 +3,18 @@ pub mod listeners; use anyhow::{Context, Result}; -use crate::app::{ - command_interface::{ - command_transfer_value::{support_types::Function, CommandTransferValue}, - Command, - }, - status::State, - App, -}; +use crate::app::{command_interface::Commands, status::State, App}; use cli_log::trace; use crossterm::event::Event as CrosstermEvent; -use handlers::{command, function, input, lua_command, matrix, setup}; -use tokio::sync::oneshot; +use handlers::{command, input, lua_command, matrix, setup}; #[derive(Debug)] pub enum Event { InputEvent(CrosstermEvent), MatrixEvent(matrix_sdk::deserialized_responses::SyncResponse), - CommandEvent(Command, Option>), + // FIXME(@soispha): The `String` is also wrong <2024-05-03> + CommandEvent(Commands, Option>), LuaCommand(String), - Function(Function), } impl Event { @@ -37,13 +29,13 @@ impl Event { .await .with_context(|| format!("Failed to handle command event: `{:#?}`", event)), - Event::LuaCommand(lua_code) => lua_command::handle(app, lua_code.to_owned()) - .await - .with_context(|| format!("Failed to handle lua code: `{}`", lua_code)), - Event::Function(function) => function::handle(app, function.to_owned()) - .await - .with_context(|| format!("Failed to handle function: `{}`", function)), - + Event::LuaCommand(lua_code) => Ok(EventStatus::Terminate), + // lua_command::handle(app, lua_code.to_owned()) + // .await + // .with_context(|| format!("Failed to handle lua code: `{}`", lua_code)), + // Event::Function(function) => function::handle(app, function.to_owned()) + // .await + // .with_context(|| format!("Failed to handle function: `{}`", function)), Event::InputEvent(event) => match app.status.state() { State::Setup => setup::handle(app, &event).await.with_context(|| { format!("Failed to handle input (setup) event: `{:#?}`", event) diff --git a/src/app/mod.rs b/src/app/mod.rs index 8d62176..628d86f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -6,6 +6,7 @@ pub mod status; use std::{ collections::HashMap, path::{Path, PathBuf}, + sync::OnceLock, }; use anyhow::{Context, Error, Result}; @@ -13,12 +14,12 @@ use cli_log::{info, warn}; use directories::ProjectDirs; use keymaps::trie::Node; use matrix_sdk::Client; -use tokio::sync::mpsc; +use tokio::sync::mpsc::{self, Sender}; use tokio_util::sync::CancellationToken; -use self::command_interface::{ - command_transfer_value::support_types::Function, lua_command_manager::LuaCommandManager, -}; +// use self::command_interface::{ +// lua_command_manager::LuaCommandManager, +// }; use crate::{ accounts::{Account, AccountsManager}, @@ -40,13 +41,14 @@ pub struct App<'runtime> { input_listener_killer: CancellationToken, matrix_listener_killer: CancellationToken, - lua: LuaCommandManager, - + // lua: LuaCommandManager, project_dirs: ProjectDirs, - key_mappings: HashMap>, + key_mappings: HashMap>, } +pub static COMMAND_TRANSMITTER: OnceLock> = OnceLock::new(); + impl App<'_> { pub fn new() -> Result { let path: &std::path::Path = Path::new("userdata/accounts.json"); @@ -58,6 +60,11 @@ impl App<'_> { }; let (tx, rx) = mpsc::channel(256); + + COMMAND_TRANSMITTER + .set(tx.clone()) + .expect("The cell should always be empty at this point"); + Ok(Self { ui: central::UI::new()?, accounts_manager: AccountsManager::new(config)?, @@ -68,7 +75,7 @@ impl App<'_> { input_listener_killer: CancellationToken::new(), matrix_listener_killer: CancellationToken::new(), - lua: LuaCommandManager::new(tx), + // lua: LuaCommandManager::new(tx), // TODO: We probably want to populate the strings below a bit more <2023-09-09> project_dirs: ProjectDirs::from("", "", "trinitrix").context( diff --git a/src/bin/api.rs b/src/bin/api.rs new file mode 100644 index 0000000..51ddb3f --- /dev/null +++ b/src/bin/api.rs @@ -0,0 +1,4 @@ +fn main() { + let output = include_str!(concat!(env!("OUT_DIR"), "/api.rs")); + println!("{}", output); +} diff --git a/src/cli.rs b/src/cli.rs index 6680486..deb5ac8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,22 +2,22 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; -// TODO: The description could be better +// TODO: The description is wrong + /// A terminal client for the matrix chat protocol #[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] +#[command(author, version, about, long_about = None)] pub struct Args { #[command(subcommand)] /// The subcommand to execute, default is start pub subcommand: Option, - #[clap(value_parser, long, short)] + #[arg(long, short)] /// Path to the Lua config file, executed instead of the normal one pub lua_config_file: Option, } #[derive(Subcommand, Debug)] pub enum Command { - #[clap(value_parser)] /// Starts the main TUI client Start {}, } diff --git a/src/main.rs b/src/main.rs index 8c56f5c..0e05c49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,3 +22,8 @@ async fn main() -> anyhow::Result<()> { Ok(()) } + +// FIXME(@soispha): Re-exports for trixy, this should be configurable <2024-05-03> +pub use crate::app::command_interface::handle_cmd; +pub use crate::app::command_interface::Commands; +pub use crate::app::command_interface::*;