1 /++
2     This is an example toy plugin to showcase how one could be written to react
3     to non-`!command` messages.
4 
5     In the first approach (version `MatchByStringComparison`), the function is
6     annotated to be called on all channel messages, and the body has to decide
7     whether or not to react to it and reply.
8 
9     In the second approach (version `MatchWithRegex`), the function is only called
10     if the incoming message matched its regular expression, so the body can safely
11     assume it should always react and reply.
12 
13     See_Also:
14         [kameloso.plugins.common.core],
15         [kameloso.plugins.common.misc]
16 
17     Copyright: [JR](https://github.com/zorael)
18     License: [Boost Software License 1.0](https://www.boost.org/users/license.html)
19 
20     Authors:
21         [JR](https://github.com/zorael)
22  +/
23 module kameloso.plugins.same;
24 
25 version(WithSamePlugin):
26 
27 // Pick *one*.
28 version = MatchByStringComparison;
29 //version = MatchWithRegex;
30 
31 private:
32 
33 import kameloso.plugins;
34 import kameloso.plugins.common;
35 import kameloso.messaging;
36 import dialect.defs;
37 
38 
39 // SameSettings
40 /++
41     Settings for the Same plugin, to toggle it on or off.
42  +/
43 @Settings struct SameSettings
44 {
45     /// Whether or not the Same plugin should react to events at all.
46     @Enabler bool enabled = true;
47 }
48 
49 
50 /+
51     Ensure that one and only one of the matching versions is declared.
52  +/
53 version(MatchByStringComparison)
54 {
55     version(MatchWithRegex)
56     {
57         version = MatchVersionError;
58     }
59 }
60 else version(MatchWithRegex)
61 {
62     version(MatchByStringComparison)
63     {
64         version = MatchVersionError;
65     }
66 }
67 else
68 {
69     version = MatchVersionError;
70 }
71 
72 
73 /+
74     Error out during compilation if the matching versions aren't sane.
75  +/
76 version(MatchVersionError)
77 {
78     import std.format : format;
79 
80     enum pattern = "`%s` needs one of versions `MatchByStringComparison` and `MatchWithRegex` (but not both)";
81     enum message = pattern.format(__MODULE__);
82     static assert(0, message);
83 }
84 
85 
86 // onAnyMessage
87 /++
88     Reacts to the message "same" by agreeing with "same".
89 
90     Uses manual matching. It is up to the function to decide whether or not it
91     should reply.
92 
93     Only literal matching is made, so matches are case-sensitive and may not be
94     trailed by other text. Only messages whose contents are literally the characters
95     "same" are matched.
96  +/
97 version(MatchByStringComparison)
98 @(IRCEventHandler()
99     .onEvent(IRCEvent.Type.CHAN)
100     .permissionsRequired(Permissions.ignore)
101     .channelPolicy(ChannelPolicy.home)
102 )
103 void onAnyMessage(SamePlugin plugin, const ref IRCEvent event)
104 {
105     // Reply only if we should
106     if (event.content == "same")
107     {
108         chan(plugin.state, event.channel, "same");
109     }
110 }
111 
112 
113 // onAnyMessageRegex
114 /++
115     Reacts to the messages which match the text "same" with some optional
116     punctuation afterwards.
117 
118     Uses the regular expression `"^same[!.]*$"`.
119  +/
120 version(MatchWithRegex)
121 @(IRCEventHandler()
122     .onEvent(IRCEvent.Type.CHAN)
123     .permissionsRequired(Permissions.ignore)
124     .channelPolicy(ChannelPolicy.home)
125     .addRegex(
126         IRCEventHandler.Regex()
127             .policy(PrefixPolicy.direct)
128             .expression(r"^same[!.]*$")
129             .description("Same.")
130     )
131 )
132 void onAnyMessageRegex(SamePlugin plugin, const ref IRCEvent event)
133 {
134     // Reply always, since the function wouldn't have been called if the message didn't match
135     chan(plugin.state, event.channel, event.content);
136 }
137 
138 
139 mixin PluginRegistration!SamePlugin;
140 
141 public:
142 
143 
144 // SamePlugin
145 /++
146     The Same toy plugin, that replies to the text "same" with "same".
147  +/
148 final class SamePlugin : IRCPlugin
149 {
150     /// All Same plugin settings gathered.
151     SameSettings sameSettings;
152 
153     mixin IRCPluginImpl;
154 }