From 50b9a8dac497656e1b611deaa9bcf9a1c1b3ece9 Mon Sep 17 00:00:00 2001 From: aria Date: Mon, 7 Jul 2025 22:07:21 +1000 Subject: [PATCH] feat(main): add txt output --- src/main.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index e571585..385e9d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,50 +1,117 @@ -use std::{fs, process::exit}; +use std::{fs::{self, File}, io::Write, process::exit}; +use anyhow::{Error, Result}; use clap::Parser; use dialoguer::MultiSelect; use once_cell::sync::Lazy; -use anyhow::{Error, Result}; -use rayon::{iter::ParallelIterator, str::ParallelString}; +use rayon::{ + iter::{IntoParallelIterator, ParallelIterator}, + str::ParallelString, +}; use regex::Regex; /// Simple program to greet a person #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { - #[arg(short, long, help="Path to log file")] - path: String, + #[arg(short, long, help = "Path to log file")] + input: String, + #[arg( + short, + long, + help = "Format of output file", + default_value_t, + value_enum + )] + format: OutputFormat, + + #[arg(short, long, help = "Path to output file")] + output: String, } +#[derive(clap::ValueEnum, Debug, Clone, Default)] +enum OutputFormat { + Image, + CSV, + #[default] + TXT, +} /// follow up by extracting just the user and the message -static SECOND_RE: Lazy = Lazy::new(|| Regex::new(r"<.*> .*").unwrap()); +static EXTRACT_MSG: Lazy = Lazy::new(|| Regex::new(r"<.*> .*").unwrap()); +static EXTRACT_TIME: Lazy = Lazy::new(|| Regex::new(r"^\[.*?\]").unwrap()); fn main() -> Result<()> { let args = Args::parse(); - if !fs::exists(&args.path)? { + if !fs::exists(&args.input)? { println!("Please provide a valid file path!"); exit(1) } - let log_contents = fs::read_to_string(args.path)?; + let log_contents = fs::read_to_string(&args.input)?; let split_log = log_contents.par_split('\n'); let filtered_log: Vec<&str> = split_log.filter(|x| is_possible_chat_msg(x)).collect(); - let selection = MultiSelect::new().with_prompt("What messages do you want to render?").items(&filtered_log).interact()?; + let extracted: Vec = filtered_log + .clone() + .into_par_iter() + .map(|x| { + format!( + "{} {}", + EXTRACT_TIME + .captures(x) + .expect("Unable to extract time") + .get(0) + .unwrap() + .as_str(), + EXTRACT_MSG + .captures(x) + .expect("Unable to extract message") + .get(0) + .unwrap() + .as_str() + ) + }) + .collect(); + let selection = MultiSelect::new() + .with_prompt("What messages do you want to render?") + .items(&extracted) + .interact()?; + match &args.format { + OutputFormat::Image => todo!(), + OutputFormat::CSV => todo!(), + OutputFormat::TXT => save_txt_file(&args.output, extracted, selection)?, + } Ok(()) } +fn save_txt_file(output: &String, extracted: Vec, selection: Vec) -> Result<(), Error> { + let mut out_file = File::create(output)?; + Ok(for msg in selection { + out_file.write(extracted[msg].as_bytes())?; + out_file.write(b"\n")?; + }) +} + fn is_possible_chat_msg(input: &str) -> bool { /// first pass to find all possible lines that could have a chat message - static SERVER_MSG_RE: Lazy = Lazy::new(|| Regex::new(r"\[.*\] \[Server thread\/INFO\] \[net.minecraft.server.MinecraftServer\/\]: <.*>*").unwrap()); - static CLIENT_MSG_RE: Lazy = Lazy::new(|| Regex::new(r"\[.*\] \[Render thread\/INFO\] \[minecraft\/ChatComponent\]: \[CHAT\] <.*>*").unwrap()); + static SERVER_MSG_RE: Lazy = Lazy::new(|| { + Regex::new( + r"\[.*\] \[Server thread\/INFO\] \[net.minecraft.server.MinecraftServer\/\]: <.*>*", + ) + .unwrap() + }); + static CLIENT_MSG_RE: Lazy = Lazy::new(|| { + Regex::new(r"\[.*\] \[Render thread\/INFO\] \[minecraft\/ChatComponent\]: \[CHAT\] <.*>*") + .unwrap() + }); return SERVER_MSG_RE.is_match(input) || CLIENT_MSG_RE.is_match(input); -} \ No newline at end of file +}