Compare commits
2 Commits
55316f295d
...
a39a0875a3
Author | SHA1 | Date |
---|---|---|
Benedikt Peetz | a39a0875a3 | |
Benedikt Peetz | 6ef6bea61c |
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
22
Cargo.toml
|
@ -3,6 +3,7 @@ name = "trinitrix"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
default-run = "trinitrix"
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
|
@ -11,16 +12,22 @@ default = ["tui"]
|
||||||
tui = ["dep:tui", "dep:tui-textarea", "dep:crossterm", "dep:tokio-util", "dep:serde", "dep:indexmap"]
|
tui = ["dep:tui", "dep:tui-textarea", "dep:crossterm", "dep:tokio-util", "dep:serde", "dep:indexmap"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
cli-log = "2.0"
|
cli-log = "2.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
matrix-sdk = "0.6"
|
matrix-sdk = "0.6"
|
||||||
tokio = { version = "1.35", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.37", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
# config
|
||||||
|
trinitry = {version = "0.1.0"}
|
||||||
|
keymaps = {version = "0.1.1", features = ["crossterm"] }
|
||||||
|
|
||||||
|
# c api
|
||||||
|
libloading = "0.8.3"
|
||||||
|
trixy = {version = "0.1.0"}
|
||||||
|
|
||||||
# lua stuff
|
# lua stuff
|
||||||
trixy = { path = "./trixy" }
|
mlua = { version = "0.9.7", features = ["lua54", "async", "send", "serialize"] }
|
||||||
keymaps = { path = "./keymaps", features = ["crossterm"] }
|
|
||||||
mlua = { version = "0.9.2", features = ["lua54", "async", "send", "serialize"] }
|
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
|
|
||||||
# tui feature specific parts
|
# tui feature specific parts
|
||||||
|
@ -29,11 +36,14 @@ tui-textarea = { version = "0.2", features = ["crossterm"], optional = true }
|
||||||
crossterm = { version = "0.25", optional = true }
|
crossterm = { version = "0.25", optional = true }
|
||||||
tokio-util = { version = "0.7", optional = true }
|
tokio-util = { version = "0.7", optional = true }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
indexmap = { version = "2.1.0", optional = true }
|
indexmap = { version = "2.2.6", optional = true }
|
||||||
directories = "5.0.1"
|
directories = "5.0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
trixy = { version = "0.1.0" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
24
flake.lock
24
flake.lock
|
@ -7,11 +7,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702488130,
|
"lastModified": 1714536327,
|
||||||
"narHash": "sha256-Bz4KTuBARAQY8952CpmYVD9o/LoScYjdw8KrK2OjEoA=",
|
"narHash": "sha256-zu4+LcygJwdyFHunTMeDFltBZ9+hoWvR/1A7IEy7ChA=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "33dbb6a8342e1cf6252c8976d02ff8a7632aa071",
|
"rev": "3124551aebd8db15d4560716d4f903bd44c64e4a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -41,11 +41,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701680307,
|
"lastModified": 1710146030,
|
||||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -56,11 +56,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702272962,
|
"lastModified": 1714656196,
|
||||||
"narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
|
"narHash": "sha256-kjQkA98lMcsom6Gbhw8SYzmwrSo+2nruiTcTZp5jK7o=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d",
|
"rev": "94035b482d181af0a0f8f77823a790b256b7c3cc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -89,11 +89,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702520151,
|
"lastModified": 1714702555,
|
||||||
"narHash": "sha256-jxJWosN7hgcW+dFT8V3EBDCYUOjv5tpjEBRmlakS7tU=",
|
"narHash": "sha256-/NoUbE5S5xpK1FU3nlHhQ/tL126+JcisXdzy3Ng4pDU=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "d6a1d8f80dbcda4c13993b859a3574c3dde61072",
|
"rev": "7f0e3ef7b7fbed78e12e5100851175d28af4b7c6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -68,6 +68,8 @@
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
pkg-config
|
pkg-config
|
||||||
mold-wrapped
|
mold-wrapped
|
||||||
|
|
||||||
|
clang-tools
|
||||||
];
|
];
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
openssl
|
openssl
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 - 2024:
|
||||||
|
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//// 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<String>);
|
||||||
|
|
||||||
|
//// 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:
|
||||||
|
/// "<C-a>ba" => "Ctrl+a" then "b" then "a"
|
||||||
|
/// "<S-a>" => "A" or "Shift+a"
|
||||||
|
/// "A" => "A"
|
||||||
|
/// "<M-a> " => "Alt+a" (<A-a>) or "Meta+a"(<M-a>) (most terminals can't really differentiate between these characters)
|
||||||
|
/// "a<C-b><C-a>" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super)
|
||||||
|
/// "<CSM-b>" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter)
|
||||||
|
/// "a " => "a" then a literal space (" ")
|
||||||
|
/// "å🙂" => "å" then "🙂" (full Unicode support!)
|
||||||
|
/// "<ESC>" => escape key
|
||||||
|
/// "<F3>" => F3 key
|
||||||
|
/// "<BACKSPACE>" => backspace key (and so forth)
|
||||||
|
/// "<DASH>" => a literal "-"
|
||||||
|
/// "<ANGULAR_BRACKET_OPEN>" or "<ABO>" => a literal "<"
|
||||||
|
/// "<ANGULAR_BRACKET_CLOSE>" or "<ABC>" => 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
|
|
@ -1,8 +0,0 @@
|
||||||
%s/::core::fmt::Formatter::debug_tuple_field1_finish(f,\(.*\))/println!(\1); return Ok(())
|
|
||||||
|
|
||||||
%s/::alloc::fmt::format(format_args!(\n\s*\(".*"\),\n\s*\(".*"\),\n\s*));/format!(\1,\2);
|
|
||||||
%s/::alloc::fmt::format(format_args!(\n\s*\(".*"\),\n\s*\(".*"\)\n\s*));/format!(\1,\2);
|
|
||||||
%s/::alloc::fmt::format(format_args!(\(".*"\), \(".*"\)));/format!(\1,\2);
|
|
||||||
|
|
||||||
%s/let lvl = ::log::Level::Info;\n\s*if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {\(\n\s*.*\)\{12}//g
|
|
||||||
%s/::log::__private_api::Option::None,\n\s*);\n\s*}/
|
|
|
@ -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?
|
include!(concat!(env!("OUT_DIR"), "/api.rs"));
|
||||||
// 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;
|
|
||||||
|
|
||||||
parse_command_enum! {
|
pub fn handle_cmd(cmd: Commands) {
|
||||||
commands {
|
let tx = COMMAND_TRANSMITTER
|
||||||
/// Prints to the output, with a newline.
|
.get()
|
||||||
// HACK(@soispha): The stdlib Lua `print()` function has stdout as output hardcoded,
|
.expect("The cell should always be populated, at this point");
|
||||||
// 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),
|
|
||||||
|
|
||||||
namespace trinitrix {
|
// FIXME: The None here is definitely wrong <2024-05-03>
|
||||||
/// Language specific functions, which mirror the `trinitrix.api` namespace.
|
tx.send(Event::CommandEvent(cmd, None));
|
||||||
/// 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<String>),
|
|
||||||
|
|
||||||
// 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:
|
|
||||||
/// "<C-a>ba" => "Ctrl+a" then "b" then "a"
|
|
||||||
/// "<S-a>" => "A" or "Shift+a"
|
|
||||||
/// "A" => "A"
|
|
||||||
/// "<M-a> " => "Alt+a" (<A-a>) or "Meta+a"(<M-a>) (most terminals can't really differentiate between these characters)
|
|
||||||
/// "a<C-b><C-a>" => "a" then "Ctrl+b" then "Ctrl+a" (also works for Shift, Alt and Super)
|
|
||||||
/// "<CSM-b>" => "Ctrl+Shift+Alt+b" (the ordering doesn't matter)
|
|
||||||
/// "a " => "a" then a literal space (" ")
|
|
||||||
/// "å🙂" => "å" then "🙂" (full Unicode support!)
|
|
||||||
/// "<ESC>" => escape key
|
|
||||||
/// "<F3>" => F3 key
|
|
||||||
/// "<BACKSPACE>" => backspace key (and so forth)
|
|
||||||
/// "<DASH>" => a literal "-"
|
|
||||||
/// "<ANGULAR_BRACKET_OPEN>" or "<ABO>" => a literal "<"
|
|
||||||
/// "<ANGULAR_BRACKET_CLOSE>" or "<ABC>" => 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(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod command_list;
|
pub mod command_list;
|
||||||
pub mod command_transfer_value;
|
// pub mod command_transfer_value;
|
||||||
pub mod lua_command_manager;
|
// pub mod lua_command_manager;
|
||||||
|
|
||||||
pub use command_list::*;
|
pub use command_list::*;
|
||||||
|
|
|
@ -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 cli_log::{info, trace, warn};
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use keymaps::{
|
use keymaps::{
|
||||||
key_repr::{Key, Keys},
|
key_repr::{Key, Keys},
|
||||||
trie::Node,
|
trie::Node,
|
||||||
};
|
};
|
||||||
use tokio::sync::oneshot;
|
use trixy::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,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
app: &mut App<'_>,
|
app: &mut App<'_>,
|
||||||
command: &Command,
|
command: &Commands,
|
||||||
output_callback: Option<oneshot::Sender<CommandTransferValue>>,
|
|
||||||
|
// FIXME(@soispha): The `String` is temporary <2024-05-03>
|
||||||
|
output_callback: Option<oneshot::Sender<String>>,
|
||||||
) -> Result<EventStatus> {
|
) -> Result<EventStatus> {
|
||||||
// A command can both return _status output_ (what you would normally print to stderr)
|
// 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).
|
// 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),+))
|
app.status.add_error_message(format!($str, $($args),+))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
macro_rules! send_main_output {
|
// macro_rules! send_main_output {
|
||||||
($str:expr) => {
|
// ($str:expr) => {
|
||||||
if let Some(sender) = output_callback {
|
// if let Some(sender) = output_callback {
|
||||||
sender
|
// sender
|
||||||
.send(CommandTransferValue::from($str))
|
// .send(CommandTransferValue::from($str))
|
||||||
.map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?;
|
// .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
($str:expr, $($args:ident),+) => {
|
// ($str:expr, $($args:ident),+) => {
|
||||||
if let Some(sender) = output_callback {
|
// if let Some(sender) = output_callback {
|
||||||
sender
|
// sender
|
||||||
.send(CommandTransferValue::from(format!($str, $($args),+)))
|
// .send(CommandTransferValue::from(format!($str, $($args),+)))
|
||||||
.map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?;
|
// .map_err(|e| Error::msg(format!("Failed to send command main output: `{}`", e)))?;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
trace!("Handling command: {:#?}", command);
|
trace!("Handling command: {:#?}", command);
|
||||||
|
|
||||||
Ok(match command {
|
Ok(match command {
|
||||||
Command::Print(output) => {
|
Commands::Trinitrix(trinitrix) => match trinitrix {
|
||||||
let output_str: String = output.to_string();
|
Trinitrix::Stdi(_) => {
|
||||||
send_status_output!(output_str);
|
// No-op I guess
|
||||||
EventStatus::Ok
|
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 {
|
Trinitrix::Api(api) => match api {
|
||||||
Api::Exit => {
|
Api::exit => {
|
||||||
send_status_output!("Terminating the application..");
|
send_status_output!("Terminating the application..");
|
||||||
EventStatus::Terminate
|
EventStatus::Terminate
|
||||||
}
|
}
|
||||||
Api::RoomMessageSend(msg) => {
|
Api::room_message_send { message } => {
|
||||||
if let Some(room) = app.status.room_mut() {
|
if let Some(room) = app.status.room_mut() {
|
||||||
room.send(msg.clone()).await?;
|
room.send(message.clone()).await?;
|
||||||
send_status_output!("Sent message: `{}`", msg);
|
send_status_output!("Sent message: `{}`", message);
|
||||||
} else {
|
} else {
|
||||||
// FIXME(@soispha): This should raise an error within lua, as it would
|
// FIXME(@soispha): This should raise an error within lua, as it would
|
||||||
// otherwise be very confusing <2023-09-20>
|
// 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
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
Api::Help(_) => todo!(),
|
|
||||||
Api::Ui(ui) => match ui {
|
Api::Ui(ui) => match ui {
|
||||||
Ui::CommandLineShow => {
|
Ui::set_mode { mode } => match mode {
|
||||||
app.ui.cli_enable();
|
Mode::Normal => {
|
||||||
app.status.set_state(State::Command);
|
app.status.set_state(State::Normal);
|
||||||
send_status_output!("CLI online");
|
send_status_output!("Set input mode to Normal");
|
||||||
EventStatus::Ok
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
Ui::CommandLineHide => {
|
Mode::Insert => {
|
||||||
app.ui.cli_disable();
|
app.status.set_state(State::Insert);
|
||||||
send_status_output!("CLI offline");
|
app.ui.set_input_position(InputPosition::MessageCompose);
|
||||||
EventStatus::Ok
|
send_status_output!("Set input mode to Insert");
|
||||||
}
|
EventStatus::Ok
|
||||||
Ui::CyclePlanes => {
|
}
|
||||||
|
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();
|
app.ui.cycle_main_input_position();
|
||||||
send_status_output!("Switched main input position");
|
send_status_output!("Switched main input position");
|
||||||
EventStatus::Ok
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
Ui::CyclePlanesRev => {
|
Ui::cycle_planes_rev => {
|
||||||
app.ui.cycle_main_input_position_rev();
|
app.ui.cycle_main_input_position_rev();
|
||||||
send_status_output!("Switched main input position; reversed");
|
send_status_output!("Switched main input position; reversed");
|
||||||
EventStatus::Ok
|
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 {
|
Api::Keymaps(keymaps) => match keymaps {
|
||||||
Keymaps::Add((mode, key, callback)) => {
|
Keymaps::add {
|
||||||
|
mode,
|
||||||
|
key,
|
||||||
|
callback,
|
||||||
|
} => {
|
||||||
mode.chars().for_each(|char| {
|
mode.chars().for_each(|char| {
|
||||||
info!("Setting keymaping ('{}') for mode '{}'", key, char);
|
info!("Setting keymaping ('{}') for mode '{}'", key, char);
|
||||||
let parsed_keys = key
|
let parsed_keys = key
|
||||||
|
@ -179,7 +164,7 @@ pub async fn handle(
|
||||||
}
|
}
|
||||||
trie.insert(&parsed_keys, callback.to_owned())
|
trie.insert(&parsed_keys, callback.to_owned())
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
send_error_output!(err.to_string());
|
send_error_output!(format!("{:#?}", err));
|
||||||
})
|
})
|
||||||
.expect("We already dealt with the error")
|
.expect("We already dealt with the error")
|
||||||
}
|
}
|
||||||
|
@ -187,60 +172,140 @@ pub async fn handle(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mem::forget(key);
|
||||||
|
mem::forget(mode);
|
||||||
EventStatus::Ok
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
// TODO(@soispha): Well.., we should probably add these functions: <2023-10-15>
|
// FIXME(@soispha): It would be nice to have these functions, but well..
|
||||||
Keymaps::Remove((mode, key)) => todo!(),
|
// someone needs to write them <2024-05-03>
|
||||||
Keymaps::Get(mode) => todo!(),
|
Keymaps::remove { mode, key } => todo!(),
|
||||||
|
Keymaps::get { mode } => todo!(),
|
||||||
},
|
},
|
||||||
Api::Raw(raw) => match raw {
|
Api::Raw(raw) => match raw {
|
||||||
Raw::RaiseError(err) => {
|
Raw::raise_error { error_message } => {
|
||||||
send_error_output!(err);
|
send_error_output!(error_message);
|
||||||
|
mem::forget(error_message);
|
||||||
EventStatus::Ok
|
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.
|
// 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
|
// Lua commands already receive the output. This should probably be communicated
|
||||||
// better, should it?
|
// better, should it?
|
||||||
send_status_output!(output);
|
send_status_output!(output_message);
|
||||||
|
mem::forget(output_message);
|
||||||
EventStatus::Ok
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
Raw::Private(_) => {
|
Raw::send_input_unprocessed { input } => {
|
||||||
// no-op, read the comment about it in the `command_list`
|
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
|
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
|
||||||
|
// }
|
||||||
|
// },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use anyhow::Result;
|
// use anyhow::Result;
|
||||||
|
//
|
||||||
use crate::app::{
|
// use crate::app::{
|
||||||
command_interface::command_transfer_value::support_types::Function, events::EventStatus, 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
|
// // 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>
|
// // future versions house check for the language the function came from <2023-10-15>
|
||||||
pub async fn handle(app: &mut App<'_>, function: Function) -> Result<EventStatus> {
|
// pub async fn handle(app: &mut App<'_>, function: Function) -> Result<EventStatus> {
|
||||||
app.lua.execute_function(function).await;
|
// app.lua.execute_function(function).await;
|
||||||
|
//
|
||||||
Ok(EventStatus::Ok)
|
// Ok(EventStatus::Ok)
|
||||||
}
|
// }
|
||||||
|
|
|
@ -4,7 +4,13 @@ use crossterm::event::Event as CrosstermEvent;
|
||||||
use keymaps::key_repr::{Key, Keys};
|
use keymaps::key_repr::{Key, Keys};
|
||||||
|
|
||||||
use crate::app::{
|
use crate::app::{
|
||||||
command_interface::{Api::Raw, Command, Raw::SendInputUnprocessed, Trinitrix::Api},
|
command_interface::{
|
||||||
|
trinitrix::{
|
||||||
|
api::{raw::Raw, Api},
|
||||||
|
Trinitrix,
|
||||||
|
},
|
||||||
|
Commands,
|
||||||
|
},
|
||||||
events::{Event, EventStatus},
|
events::{Event, EventStatus},
|
||||||
status::State,
|
status::State,
|
||||||
App,
|
App,
|
||||||
|
@ -24,7 +30,11 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
|
||||||
for key in pending_keys {
|
for key in pending_keys {
|
||||||
app.tx
|
app.tx
|
||||||
.send(Event::CommandEvent(
|
.send(Event::CommandEvent(
|
||||||
Command::Trinitrix(Api(Raw(SendInputUnprocessed(key.to_string_repr())))),
|
Commands::Trinitrix(Trinitrix::Api(Api::Raw(
|
||||||
|
Raw::send_input_unprocessed {
|
||||||
|
input: key.to_string_repr(),
|
||||||
|
},
|
||||||
|
))),
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -34,9 +44,9 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
|
||||||
// Just let the input event slip through if no keymap matches
|
// Just let the input event slip through if no keymap matches
|
||||||
app.tx
|
app.tx
|
||||||
.send(Event::CommandEvent(
|
.send(Event::CommandEvent(
|
||||||
Command::Trinitrix(Api(Raw(SendInputUnprocessed(
|
Commands::Trinitrix(Trinitrix::Api(Api::Raw(Raw::send_input_unprocessed {
|
||||||
converted_key.to_string_repr(),
|
input: converted_key.to_string_repr(),
|
||||||
)))),
|
}))),
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -88,7 +98,9 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
|
||||||
let function = possible_key_map
|
let function = possible_key_map
|
||||||
.value()
|
.value()
|
||||||
.expect("This node is terminal and a child, it should have a value");
|
.expect("This node is terminal and a child, it should have a value");
|
||||||
app.tx.send(Event::Function(*function)).await?;
|
|
||||||
|
function();
|
||||||
|
// app.tx.send(Event::Function(*function)).await?;
|
||||||
app.status.set_state(old_state.to_owned());
|
app.status.set_state(old_state.to_owned());
|
||||||
} else {
|
} else {
|
||||||
// The choice does not have a value attached to it (might be a waypoint)
|
// The choice does not have a value attached to it (might be a waypoint)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use anyhow::Result;
|
// use anyhow::Result;
|
||||||
use cli_log::trace;
|
// use cli_log::trace;
|
||||||
|
//
|
||||||
use crate::app::{events::EventStatus, App};
|
// use crate::app::{events::EventStatus, App};
|
||||||
|
//
|
||||||
// This function is here mainly to reserve this spot for further processing of the lua command.
|
// // 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
|
// // TODO(@Soispha): Move the lua executor thread code from app to this module
|
||||||
pub async fn handle(app: &mut App<'_>, command: String) -> Result<EventStatus> {
|
// pub async fn handle(app: &mut App<'_>, command: String) -> Result<EventStatus> {
|
||||||
trace!("Recieved ci command: `{command}`; executing..");
|
// trace!("Recieved ci command: `{command}`; executing..");
|
||||||
|
//
|
||||||
app.lua.execute_code(command).await;
|
// app.lua.execute_code(command).await;
|
||||||
|
//
|
||||||
Ok(EventStatus::Ok)
|
// Ok(EventStatus::Ok)
|
||||||
}
|
// }
|
||||||
|
|
|
@ -8,4 +8,4 @@ pub mod matrix;
|
||||||
// ci
|
// ci
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod lua_command;
|
pub mod lua_command;
|
||||||
pub mod function;
|
// pub mod function;
|
||||||
|
|
|
@ -3,26 +3,18 @@ pub mod listeners;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use crate::app::{
|
use crate::app::{command_interface::Commands, status::State, App};
|
||||||
command_interface::{
|
|
||||||
command_transfer_value::{support_types::Function, CommandTransferValue},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
status::State,
|
|
||||||
App,
|
|
||||||
};
|
|
||||||
use cli_log::trace;
|
use cli_log::trace;
|
||||||
use crossterm::event::Event as CrosstermEvent;
|
use crossterm::event::Event as CrosstermEvent;
|
||||||
use handlers::{command, function, input, lua_command, matrix, setup};
|
use handlers::{command, input, lua_command, matrix, setup};
|
||||||
use tokio::sync::oneshot;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
InputEvent(CrosstermEvent),
|
InputEvent(CrosstermEvent),
|
||||||
MatrixEvent(matrix_sdk::deserialized_responses::SyncResponse),
|
MatrixEvent(matrix_sdk::deserialized_responses::SyncResponse),
|
||||||
CommandEvent(Command, Option<oneshot::Sender<CommandTransferValue>>),
|
// FIXME(@soispha): The `String` is also wrong <2024-05-03>
|
||||||
|
CommandEvent(Commands, Option<trixy::oneshot::Sender<String>>),
|
||||||
LuaCommand(String),
|
LuaCommand(String),
|
||||||
Function(Function),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
|
@ -37,13 +29,13 @@ impl Event {
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to handle command event: `{:#?}`", event)),
|
.with_context(|| format!("Failed to handle command event: `{:#?}`", event)),
|
||||||
|
|
||||||
Event::LuaCommand(lua_code) => lua_command::handle(app, lua_code.to_owned())
|
Event::LuaCommand(lua_code) => Ok(EventStatus::Terminate),
|
||||||
.await
|
// lua_command::handle(app, lua_code.to_owned())
|
||||||
.with_context(|| format!("Failed to handle lua code: `{}`", lua_code)),
|
// .await
|
||||||
Event::Function(function) => function::handle(app, function.to_owned())
|
// .with_context(|| format!("Failed to handle lua code: `{}`", lua_code)),
|
||||||
.await
|
// Event::Function(function) => function::handle(app, function.to_owned())
|
||||||
.with_context(|| format!("Failed to handle function: `{}`", function)),
|
// .await
|
||||||
|
// .with_context(|| format!("Failed to handle function: `{}`", function)),
|
||||||
Event::InputEvent(event) => match app.status.state() {
|
Event::InputEvent(event) => match app.status.state() {
|
||||||
State::Setup => setup::handle(app, &event).await.with_context(|| {
|
State::Setup => setup::handle(app, &event).await.with_context(|| {
|
||||||
format!("Failed to handle input (setup) event: `{:#?}`", event)
|
format!("Failed to handle input (setup) event: `{:#?}`", event)
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod status;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
sync::OnceLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Error, Result};
|
use anyhow::{Context, Error, Result};
|
||||||
|
@ -13,12 +14,12 @@ use cli_log::{info, warn};
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use keymaps::trie::Node;
|
use keymaps::trie::Node;
|
||||||
use matrix_sdk::Client;
|
use matrix_sdk::Client;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc::{self, Sender};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use self::command_interface::{
|
// use self::command_interface::{
|
||||||
command_transfer_value::support_types::Function, lua_command_manager::LuaCommandManager,
|
// lua_command_manager::LuaCommandManager,
|
||||||
};
|
// };
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accounts::{Account, AccountsManager},
|
accounts::{Account, AccountsManager},
|
||||||
|
@ -40,13 +41,14 @@ pub struct App<'runtime> {
|
||||||
input_listener_killer: CancellationToken,
|
input_listener_killer: CancellationToken,
|
||||||
matrix_listener_killer: CancellationToken,
|
matrix_listener_killer: CancellationToken,
|
||||||
|
|
||||||
lua: LuaCommandManager,
|
// lua: LuaCommandManager,
|
||||||
|
|
||||||
project_dirs: ProjectDirs,
|
project_dirs: ProjectDirs,
|
||||||
|
|
||||||
key_mappings: HashMap<State, Node<Function>>,
|
key_mappings: HashMap<State, Node<extern "C" fn()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static COMMAND_TRANSMITTER: OnceLock<Sender<Event>> = OnceLock::new();
|
||||||
|
|
||||||
impl App<'_> {
|
impl App<'_> {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let path: &std::path::Path = Path::new("userdata/accounts.json");
|
let path: &std::path::Path = Path::new("userdata/accounts.json");
|
||||||
|
@ -58,6 +60,11 @@ impl App<'_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(256);
|
let (tx, rx) = mpsc::channel(256);
|
||||||
|
|
||||||
|
COMMAND_TRANSMITTER
|
||||||
|
.set(tx.clone())
|
||||||
|
.expect("The cell should always be empty at this point");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ui: central::UI::new()?,
|
ui: central::UI::new()?,
|
||||||
accounts_manager: AccountsManager::new(config)?,
|
accounts_manager: AccountsManager::new(config)?,
|
||||||
|
@ -68,7 +75,7 @@ impl App<'_> {
|
||||||
input_listener_killer: CancellationToken::new(),
|
input_listener_killer: CancellationToken::new(),
|
||||||
matrix_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>
|
// TODO: We probably want to populate the strings below a bit more <2023-09-09>
|
||||||
project_dirs: ProjectDirs::from("", "", "trinitrix").context(
|
project_dirs: ProjectDirs::from("", "", "trinitrix").context(
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
let output = include_str!(concat!(env!("OUT_DIR"), "/api.rs"));
|
||||||
|
println!("{}", output);
|
||||||
|
}
|
|
@ -2,22 +2,22 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
// TODO: The description could be better
|
// TODO: The description is wrong
|
||||||
|
|
||||||
/// A terminal client for the matrix chat protocol
|
/// A terminal client for the matrix chat protocol
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
/// The subcommand to execute, default is start
|
/// The subcommand to execute, default is start
|
||||||
pub subcommand: Option<Command>,
|
pub subcommand: Option<Command>,
|
||||||
|
|
||||||
#[clap(value_parser, long, short)]
|
#[arg(long, short)]
|
||||||
/// Path to the Lua config file, executed instead of the normal one
|
/// Path to the Lua config file, executed instead of the normal one
|
||||||
pub lua_config_file: Option<PathBuf>,
|
pub lua_config_file: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[clap(value_parser)]
|
|
||||||
/// Starts the main TUI client
|
/// Starts the main TUI client
|
||||||
Start {},
|
Start {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,3 +22,8 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
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::*;
|
||||||
|
|
Reference in New Issue