diff --git a/Cargo.toml b/Cargo.toml index 207749d..431a050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,5 @@ arrayvec = "0.7" rand = "0.8" meval = "0.2" async-circe = { git = "https://git.karx.xyz/circe/async-circe" } +lazy_static = "1.4.0" +sedregex = "0.2.5" diff --git a/src/bots/mod.rs b/src/bots/mod.rs index 4511374..81f6a61 100644 --- a/src/bots/mod.rs +++ b/src/bots/mod.rs @@ -1,3 +1,4 @@ pub mod leek; pub mod title; pub mod misc; +pub mod sed; diff --git a/src/bots/sed.rs b/src/bots/sed.rs new file mode 100644 index 0000000..ad91632 --- /dev/null +++ b/src/bots/sed.rs @@ -0,0 +1,69 @@ +use std::{fmt::Display, error::Error}; + +use arrayvec::{ArrayString, CapacityError}; +use fancy_regex::Regex; +use lazy_static::lazy_static; +use sedregex::find_and_replace; + +#[derive(Debug)] +pub enum SedErrorKind { + Capacity(CapacityError), + Regex(fancy_regex::Error), + SedRegex(sedregex::ErrorKind) +} + +#[derive(Debug)] +pub struct SedCapacityError(SedErrorKind); + +impl Display for SedCapacityError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // yeah it's ugly but there's no better way afaik + match &self.0 { + SedErrorKind::Capacity(e) => Display::fmt(e, f), + SedErrorKind::Regex(e) => Display::fmt(e, f), + SedErrorKind::SedRegex(e) => Display::fmt(e, f), + } + } +} + +impl Error for SedCapacityError {} + +impl From> for SedCapacityError { + fn from(e: CapacityError) -> Self { + Self { 0: SedErrorKind::Capacity(e.simplify()) } + } +} + +impl From for SedCapacityError { + fn from(e: fancy_regex::Error) -> Self { + Self { 0: SedErrorKind::Regex(e) } + } +} + +impl From for SedCapacityError { + fn from(e: sedregex::ErrorKind) -> Self { + Self { 0: SedErrorKind::SedRegex(e) } + } +} + +type SedResult = Result>, SedCapacityError>; + +pub fn resolve(prev_msg: &str, cmd: &str) -> SedResult { + lazy_static! { + static ref RE: Regex = Regex::new(r"^s/.*/.*").unwrap(); // yes this regex is valid, don't worry about it + } + + if RE.is_match(cmd)? { + if let Some(mat) = RE.find(cmd)? { + let slice = &cmd[mat.start()..mat.end()]; + + let formatted = find_and_replace(&prev_msg, [slice])?; + + return Ok(Some(ArrayString::from(&formatted)?)); + } else { + return Ok(None); + } + } + + Ok(None) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index fa04262..23748aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod bots; +use arrayvec::ArrayString; use async_circe::{commands::Command, Client, Config}; use bots::title::Titlebot; use bots::{leek, misc}; @@ -10,6 +11,7 @@ use std::io::Read; use std::{collections::HashMap, env}; use tokio::select; use tracing_subscriber::EnvFilter; +use std::fmt::Write; // this will be displayed when the help command is used const HELP: &[&str] = &[ @@ -167,6 +169,17 @@ async fn handle_privmsg( if let Some(titlebot_msg) = state.titlebot.resolve(&message).await? { state.client.privmsg(&channel, &titlebot_msg).await?; } + + if let Some(prev_msg) = state.last_msgs.get(&nick) { + if let Some(formatted) = bots::sed::resolve(prev_msg, &message)? { + let mut result = ArrayString::<512>::new(); + write!(result, "<{}> {}", nick, formatted)?; + state.client.privmsg(&channel, &result).await?; + state.last_msgs.insert(nick, formatted.to_string()); // yes i know this is an allocation, but the hashmap takes a string so nothing i can do + return Ok(()); + } + } + state.last_msgs.insert(nick, message); return Ok(()); }