summary refs log tree commit diff
path: root/src/system/plugin/edit.rs
blob: 1fd4e23df44de7119c2b28bf93e9814711e0630a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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<PluginCommand> {
        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<ChannelMarker>, _response: &'message Response) {
        // noop
    }
}