use async_trait::async_trait; use regex::RegexBuilder; use twilight_model::id::{marker::ChannelMarker, Id}; use twilight_model::channel::Message; use crate::system::{log::Logger, types::{Response, System}}; use super::{PluginCommand, SeancePlugin}; pub struct Edit; impl Edit { pub fn new() -> Self { Self } } #[async_trait] impl<'system> SeancePlugin<'system> for Edit { fn get_commands(&self) -> Vec { vec![ PluginCommand::Word("edit"), PluginCommand::Char("s"), ] } async fn handle_command<'message>(&self, logger: &'system Logger, system: &'system System, message: &'message Message, command: PluginCommand, args: Vec<&'message str>) { if let Some((edit_target, update_most_recent)) = system.resolve_message_target(message).await { if let Some(authoring_member) = system.get_member_by_id(edit_target.author.id).await { if let Some(edit_contents) = match command { PluginCommand::Word("edit") => Some(args.join(" ")), PluginCommand::Char("s") => async { let replacement_command = args.join(" "); let separator = replacement_command.chars().nth(1).unwrap(); let parts: Vec<&str> = replacement_command.split(separator).collect(); if parts.len() != 3 && parts.len() != 4 { None? } let pattern = parts.get(1).unwrap(); let replacement = parts.get(2).unwrap(); let flags = parts.get(3).unwrap_or(&""); let mut global = false; let mut regex = RegexBuilder::new(pattern); for flag in flags.chars() {match flag { 'i' => {regex.case_insensitive(true);}, 'm' => {regex.multi_line(true);}, 'g' => {global = true;}, 'x' => {regex.ignore_whitespace(true);}, 'R' => {regex.crlf(true);}, 's' => {regex.dot_matches_new_line(true);}, 'U' => {regex.swap_greed(true);}, other => { logger.log_err(Some(authoring_member.discord_token.clone()), format!("Unknown regex flag {other}")).await; None? }, }}; let valid_regex = regex.build(); let original_content = edit_target.content; // If the regex parses, replace with that let result = if let Ok(regex) = valid_regex { if global { regex.replace_all(original_content.as_str(), *replacement).to_string() } else { regex.replace(original_content.as_str(), *replacement).to_string() } // Else attempt replace as string } else { original_content.replace(pattern, replacement) }; Some(result) }.await, _ => unreachable!("Unknown command"), } { let result = {authoring_member.client.lock().await.update_message(edit_target.channel_id, edit_target.id) .content(Some(edit_contents.as_str())) .expect("Invalid edit contents") .await .expect("Could not edit") .model() .await .expect("Could not parse response")}; if update_most_recent { system.cache_most_recent_message(result.channel_id, result, authoring_member.clone()).await; } let _ = {authoring_member.client.lock().await.delete_message(message.channel_id, message.id).await}; } else { logger.log_err(None, format!("Could not determine edit contents")).await; } } else { logger.log_err(None, format!("Cannot edit message not sent by system member")).await; } } else { logger.log_err(None, format!("Cannot find edit target")).await; } } async fn handle_message<'message>(&self, _logger: &'system Logger, _system: &'system System, _message: &'message Message, _response: &'message mut Response) { // noop } async fn post_response<'message>(&self, _logger: &'system Logger, _system: &'system System, _message: &'message Message, _channel: Id, _response: &'message Response) { // noop } }