feat(main): implement readline functionality with rustylinez

Including background log output
This commit is contained in:
xeruf 2024-08-20 22:40:16 +03:00
parent a67bd384ec
commit 9da41db427
3 changed files with 48 additions and 17 deletions

27
Cargo.lock generated
View File

@ -302,6 +302,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -1198,6 +1204,7 @@ dependencies = [
"parse_datetime", "parse_datetime",
"regex", "regex",
"rustyline", "rustyline",
"rustylinez",
"tokio", "tokio",
"xdg", "xdg",
] ]
@ -1217,6 +1224,16 @@ dependencies = [
"smallvec", "smallvec",
] ]
[[package]]
name = "nix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
dependencies = [
"bitflags 0.4.0",
"libc",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.26.4" version = "0.26.4"
@ -1814,6 +1831,16 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "rustylinez"
version = "0.2.2"
source = "git+https://github.com/xeruf/rustylinez?rev=c2cd6178#c2cd617830fb15bd5c95c6f17809e91b95660889"
dependencies = [
"libc",
"nix 0.5.1",
"unicode-width",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.17" version = "1.0.17"

View File

@ -24,6 +24,7 @@ interim = { version = "0.1", features = ["chrono"] }
nostr-sdk = "0.34" # { git = "https://github.com/rust-nostr/nostr" } nostr-sdk = "0.34" # { git = "https://github.com/rust-nostr/nostr" }
tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "macros"] } tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "macros"] }
regex = "1.10.5" regex = "1.10.5"
rustylinez = { git = "https://github.com/xeruf/rustylinez", rev = "c2cd6178" }
[dev-dependencies] [dev-dependencies]
chrono-english = "0.1" chrono-english = "0.1"

View File

@ -3,7 +3,7 @@ use std::collections::{HashMap, VecDeque};
use std::env::{args, var}; use std::env::{args, var};
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader, stdin, stdout, Write}; use std::io::{BufRead, BufReader};
use std::iter::once; use std::iter::once;
use std::ops::Sub; use std::ops::Sub;
use std::path::PathBuf; use std::path::PathBuf;
@ -11,12 +11,14 @@ use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use colored::Colorize; use colored::Colorize;
use env_logger::Builder; use env_logger::{Builder, Target, WriteStyle};
use itertools::Itertools; use itertools::Itertools;
use log::{debug, error, info, LevelFilter, trace, warn}; use log::{debug, error, info, LevelFilter, trace, warn};
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use nostr_sdk::TagStandard::Hashtag; use nostr_sdk::TagStandard::Hashtag;
use regex::Regex; use regex::Regex;
use rustylinez::Editor;
use rustylinez::error::ReadlineError;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tokio::time::error::Elapsed; use tokio::time::error::Elapsed;
@ -138,20 +140,22 @@ pub(crate) enum MostrMessage {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let mut rl = Editor::new();
let mut args = args().skip(1).peekable(); let mut args = args().skip(1).peekable();
if args.peek().is_some_and(|arg| arg == "--debug") { if args.peek().is_some_and(|arg| arg == "--debug") {
args.next(); args.next();
Builder::new() let mut builder = Builder::new();
.filter(None, LevelFilter::Debug) builder.filter(None, LevelFilter::Debug)
//.filter(Some("mostr"), LevelFilter::Trace) //.filter(Some("mostr"), LevelFilter::Trace)
.parse_default_env() .parse_default_env();
.init(); builder
} else { } else {
colog::default_builder() let mut builder = colog::default_builder();
.filter(Some("nostr-relay-pool"), LevelFilter::Error) builder.filter(Some("nostr-relay-pool"), LevelFilter::Error);
//.filter(Some("nostr-relay-pool::relay::internal"), LevelFilter::Off) //.filter(Some("nostr-relay-pool::relay::internal"), LevelFilter::Off)
.init(); builder
} }.write_style(WriteStyle::Always).target(Target::Pipe(Box::new(rl.get_printer()))).init();
let config_dir = or_warn!(BaseDirectories::new(), "Could not determine config directory") let config_dir = or_warn!(BaseDirectories::new(), "Could not determine config directory")
.and_then(|d| or_warn!(d.create_config_directory("mostr"), "Could not create config directory")) .and_then(|d| or_warn!(d.create_config_directory("mostr"), "Could not create config directory"))
@ -292,21 +296,19 @@ async fn main() {
} }
} }
let mut lines = stdin().lines();
loop { loop {
trace!("All Root Tasks:\n{}", relays.iter().map(|(url, tasks)| trace!("All Root Tasks:\n{}", relays.iter().map(|(url, tasks)|
format!("{}: [{}]", url, tasks.children_of(None).map(|id| tasks.get_task_title(id)).join("; "))).join("\n")); format!("{}: [{}]", url, tasks.children_of(None).map(|id| tasks.get_task_title(id)).join("; "))).join("\n"));
println!(); println!();
let tasks = selected_relay.as_ref().and_then(|url| relays.get(url)).unwrap_or(&local_tasks); let tasks = selected_relay.as_ref().and_then(|url| relays.get(url)).unwrap_or(&local_tasks);
print!( let prompt = format!(
"{} {}{}) ", "{} {}{}) ",
selected_relay.as_ref().map_or("TEMP".to_string(), |url| url.to_string()).bright_black(), selected_relay.as_ref().map_or("TEMP".to_string(), |url| url.to_string()).bright_black(),
tasks.get_task_path(tasks.get_position()).bold(), tasks.get_task_path(tasks.get_position()).bold(),
tasks.get_prompt_suffix().italic(), tasks.get_prompt_suffix().italic(),
); );
stdout().flush().unwrap(); match rl.readline(&prompt) {
match lines.next() { Ok(input) => {
Some(Ok(input)) => {
let mut count = 0; let mut count = 0;
while let Ok(notification) = notifications.try_recv() { while let Ok(notification) = notifications.try_recv() {
if let RelayPoolNotification::Event { if let RelayPoolNotification::Event {
@ -629,8 +631,9 @@ async fn main() {
} }
or_warn!(tasks.print_tasks()); or_warn!(tasks.print_tasks());
} }
Some(Err(e)) => warn!("{}", e), Err(ReadlineError::Eof) => break,
None => break, Err(ReadlineError::Interrupted) => break, // TODO exit if prompt was empty, or clear
Err(e) => warn!("{}", e),
} }
} }
println!(); println!();