Feat(treewide): Add a feature based layout and repl subcommand

Compiling the whole tui stack, just to debug the lua command line seems
counterproductive to me. This allows to just compile the needed parts
for a basic lua repl.

As of yet the repl is just a mock-up, as the event handling can, as of
right now, not easily be separated from the tui.

To activate specific features add specify the on the cargo command line
like this:
```
cargo run --features "cli tui"
```
or add them to the `default` feature set in the `Cargo.toml`.
This commit is contained in:
Benedikt Peetz 2023-07-23 15:53:31 +02:00
parent 993ef6af89
commit ebb16a20de
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
29 changed files with 326 additions and 73 deletions

205
Cargo.lock generated
View File

@ -73,6 +73,55 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.72"
@ -145,9 +194,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.71"
version = "0.1.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.31",
@ -228,6 +277,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]]
name = "blake3"
version = "1.4.1"
@ -382,6 +437,47 @@ dependencies = [
"inout",
]
[[package]]
name = "clap"
version = "4.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [
"heck",
"proc-macro2 1.0.66",
"quote 1.0.31",
"syn 2.0.26",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "cli-log"
version = "2.0.0"
@ -400,9 +496,15 @@ version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "const-oid"
version = "0.7.1"
@ -486,7 +588,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"crossterm_winapi",
"libc",
"mio",
@ -690,9 +792,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.8.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "encoding_rs"
@ -738,12 +840,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "fastrand"
version = "1.9.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "file-size"
@ -1003,6 +1102,12 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.2"
@ -1194,23 +1299,23 @@ dependencies = [
"web-sys",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "ipnet"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -1267,9 +1372,9 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
[[package]]
name = "lock_api"
@ -1614,7 +1719,7 @@ version = "0.10.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cfg-if",
"foreign-types",
"libc",
@ -2064,7 +2169,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -2073,7 +2178,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -2199,7 +2304,7 @@ dependencies = [
"thiserror",
"tracing",
"url",
"uuid 1.4.0",
"uuid 1.4.1",
"wildmatch",
]
@ -2255,13 +2360,12 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.37.23"
version = "0.38.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
dependencies = [
"bitflags",
"bitflags 2.3.3",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
@ -2290,11 +2394,11 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "2.9.1"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
@ -2303,9 +2407,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.9.0"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
@ -2313,9 +2417,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.171"
version = "1.0.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1"
dependencies = [
"serde_derive",
]
@ -2331,9 +2435,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.171"
version = "1.0.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.31",
@ -2520,11 +2624,10 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.6.0"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998"
dependencies = [
"autocfg 1.1.0",
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
@ -2700,12 +2803,14 @@ name = "trinitrix"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"cli-log",
"crossterm",
"indexmap 2.0.0",
"lua_macros",
"matrix-sdk",
"mlua",
"once_cell",
"serde",
"tokio",
"tokio-util",
@ -2725,7 +2830,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cassowary",
"crossterm",
"unicode-segmentation",
@ -2808,6 +2913,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "0.7.4"
@ -2828,9 +2939,9 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be"
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [
"getrandom 0.2.10",
"wasm-bindgen",

View File

@ -6,16 +6,29 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["cli"]
full = ["cli", "tui"]
cli = ["tokio/io-std"]
tui = ["dep:tui", "dep:tui-textarea", "dep:crossterm", "dep:tokio-util", "dep:serde", "dep:indexmap"]
[dependencies]
lua_macros = { path = "./lua_macros" }
tui = "0.19"
tui-textarea = { version = "0.2", features = ["crossterm"] }
crossterm = "0.25"
matrix-sdk = "0.6"
anyhow = "1.0"
tokio = { version = "1.29", features = ["macros", "rt-multi-thread"] }
tokio-util = "0.7"
serde = "1.0"
clap = { version = "4.3.19", features = ["derive"] }
cli-log = "2.0"
indexmap = "2.0.0"
anyhow = "1.0"
matrix-sdk = "0.6"
tokio = { version = "1.29", features = ["macros", "rt-multi-thread"] }
# lua stuff
lua_macros = { path = "./lua_macros" }
mlua = { version = "0.8.9", features = ["lua54", "async", "send"] }
once_cell = "1.18.0"
# tui feature specific parts
tui = {version = "0.19", optional = true}
tui-textarea = { version = "0.2", features = ["crossterm"], optional = true }
crossterm = { version = "0.25", optional = true }
tokio-util = { version = "0.7", optional = true }
serde = { version = "1.0", optional = true }
indexmap = { version = "2.0.0", optional = true }

23
src/cli.rs Normal file
View File

@ -0,0 +1,23 @@
use clap::{Parser, Subcommand};
// TODO: The description could be better
/// A terminal client for the matrix chat protocol
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
#[command(subcommand)]
/// The subcommand to execute, default is start
pub subcommand: Option<Command>,
}
#[derive(Subcommand, Debug)]
pub enum Command {
/// Starts a repl, for the lua interface
#[cfg(feature = "cli")]
#[clap(value_parser)]
Repl {},
/// Starts the main tui client
#[cfg(feature = "tui")]
#[clap(value_parser)]
Start {},
}

View File

@ -1,13 +1,43 @@
mod accounts;
mod app;
mod ui;
mod cli;
pub mod event_handler;
#[cfg(feature = "tui")]
mod tui_app;
#[cfg(feature = "cli")]
mod repl;
use clap::Parser;
use crate::cli::{Args, Command};
#[cfg(feature = "tui")]
pub use tui_app::*;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
cli_log::init_cli_log!();
let mut app = app::App::new()?;
app.run().await?;
let args = Args::parse();
let command = args.subcommand.unwrap_or(
#[cfg(all(feature = "tui", not(feature = "cli")))]
Command::Start {},
#[cfg(all(feature = "cli", not(feature = "tui")))]
Command::Repl {},
#[cfg(all(feature = "cli", feature = "tui"))]
Command::Start {},
);
match command {
#[cfg(feature = "cli")]
Command::Repl {} => {
repl::run().await?;
}
#[cfg(feature = "tui")]
Command::Start {} => {
let mut app = app::App::new()?;
app.run().await?;
}
};
Ok(())
}

41
src/repl/mod.rs Normal file
View File

@ -0,0 +1,41 @@
use std::io::ErrorKind;
use anyhow::{Context, Result};
use cli_log::{info, warn};
use tokio::io::{stdin, stdout, AsyncReadExt, AsyncWriteExt};
pub async fn run() -> Result<()> {
let mut stdin = stdin();
let mut stdout = stdout();
let mut buffer = [0; 1];
let mut new_command = vec![];
loop {
stdout
.write("trinitrix:> ".as_bytes())
.await
.context("Failed to write prompt")?;
stdout.flush().await.context("Failed to flush prompt")?;
new_command.clear();
loop {
if let Err(err) = stdin.read_exact(&mut buffer).await {
if err.kind() == ErrorKind::UnexpectedEof {
warn!("Unexpected EOF, we assume the user quit.");
return Ok(());
} else {
Err(err).context("Failed to read next character")?;
}
}
if buffer == "\n".as_bytes() {
break;
} else {
new_command.append(&mut buffer.to_vec());
}
}
info!(
"Got user repl input: {}",
String::from_utf8(new_command.clone())
.context("Failed to convert user input to utf8 string")?
)
}
}

View File

@ -2,14 +2,17 @@ pub mod command_interface;
pub mod events;
pub mod status;
use std::{path::Path, sync::Arc};
use std::path::Path;
use anyhow::{Context, Error, Result};
use cli_log::info;
use matrix_sdk::Client;
use mlua::Lua;
use once_cell::sync::OnceCell;
use status::{State, Status};
use tokio::sync::mpsc;
use tokio::{
sync::{mpsc, Mutex},
task::LocalSet,
};
use tokio_util::sync::CancellationToken;
use crate::{
@ -31,16 +34,42 @@ pub struct App<'ui> {
input_listener_killer: CancellationToken,
matrix_listener_killer: CancellationToken,
lua: Arc<Lua>,
lua_command_tx: mpsc::Sender<String>,
}
impl App<'_> {
pub fn new() -> Result<Self> {
fn set_up_lua(tx: mpsc::Sender<Event>) -> Arc<Lua> {
let mut lua = Lua::new();
fn set_up_lua(tx: mpsc::Sender<Event>) -> mpsc::Sender<String> {
info!("Setting up Lua context..");
static LUA: OnceCell<Mutex<mlua::Lua>> = OnceCell::new();
generate_ci_functions(&mut lua, tx);
Arc::new(lua)
let (lua_command_tx, mut rx) = mpsc::channel(256);
let local_set = LocalSet::new();
local_set.spawn_local(async move {
let lua = LUA
.get_or_init(|| Mutex::new(generate_ci_functions(mlua::Lua::new(), tx)))
.lock()
.await;
info!("Initialized Lua context");
while let Some(command) = rx.recv().await {
info!("Recieved command to execute: `{}`", &command);
let output = lua
.load(&command)
// FIXME this assumes string output only
.eval_async::<String>()
.await
.with_context(|| format!("Failed to execute: `{command}`"));
info!(
"Function `{}` returned: `{}`",
command,
output.unwrap_or("<returned error>".to_owned())
);
}
});
lua_command_tx
}
let path: &std::path::Path = Path::new("userdata/accounts.json");
@ -62,7 +91,7 @@ impl App<'_> {
input_listener_killer: CancellationToken::new(),
matrix_listener_killer: CancellationToken::new(),
lua: set_up_lua(tx),
lua_command_tx: set_up_lua(tx),
})
}
@ -87,11 +116,10 @@ impl App<'_> {
self.ui.update(&self.status).await?;
let event = self.rx.recv().await.context("Failed to get next event")?;
match event.handle(self).await? {
event_types::EventStatus::Ok => (),
event_types::EventStatus::Terminate => break,
_ => (),
_ => todo!(),
};
}

7
src/tui_app/mod.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod app;
pub mod ui;
pub mod accounts;
pub use app::*;
pub use ui::*;
pub use accounts::*;