-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathcommandplugin.go
176 lines (146 loc) · 5.41 KB
/
commandplugin.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package bruxism
import (
"fmt"
"strings"
)
const commandDelimeter = "!"
// CommandHelpFunc is the function signature for command help methods.
type CommandHelpFunc func(bot *Bot, service Service, message Message) (string, string)
// CommandMessageFunc is the function signature for bot message commands.
type CommandMessageFunc func(bot *Bot, service Service, message Message, args string, parts []string)
// NewCommandHelp creates a new Command Help function.
func NewCommandHelp(args, help string) CommandHelpFunc {
return func(bot *Bot, service Service, message Message) (string, string) {
return args, help
}
}
// MatchesCommandStringPrefix returns true if a message matches a command.
// Commands will be matched ignoring case with a prefix if they are not private messages.
func MatchesCommandStringPrefix(prefix, commandString string, private bool, message string) bool {
lowerMessage := strings.ToLower(strings.TrimSpace(message))
lowerPrefix := strings.ToLower(prefix)
if strings.HasPrefix(lowerMessage, lowerPrefix) {
lowerMessage = lowerMessage[len(lowerPrefix):]
} else if !private {
return false
}
lowerMessage = strings.TrimSpace(lowerMessage)
lowerCommand := strings.ToLower(commandString)
return lowerMessage == lowerCommand || strings.HasPrefix(lowerMessage, lowerCommand+" ")
}
// MatchesCommand returns true if a message matches a command.
func MatchesCommand(service Service, commandString string, message Message) bool {
// Deleted messages can't trigger commands.
if message.Type() == MessageTypeDelete {
return false
}
prefix := service.CommandPrefix()
private := service.IsPrivate(message)
if !private {
if matches, ok := message.MatchesCommand(prefix, commandString); ok {
return matches
}
}
return MatchesCommandStringPrefix(prefix, commandString, private, message.Message())
}
// ParseCommandStringPrefix will strip all prefixes from a message string, and return that string, and a space separated tokenized version of that string.
func ParseCommandStringPrefix(prefix, message string) (string, []string) {
message = strings.TrimSpace(message)
lowerMessage := strings.ToLower(message)
lowerPrefix := strings.ToLower(prefix)
if strings.HasPrefix(lowerMessage, lowerPrefix) {
message = message[len(lowerPrefix):]
}
parts := strings.Fields(message)
if len(parts) > 1 {
parts = parts[1:]
return strings.Join(parts, " "), parts
}
return "", []string{}
}
// ParseCommand parses a message.
func ParseCommand(service Service, message Message) (string, []string) {
if rest, parts, ok := message.ParseCommand(service.CommandPrefix()); ok {
return rest, parts
}
return ParseCommandStringPrefix(service.CommandPrefix(), message.Message())
}
// CommandHelp is a helper message that creates help text for a command.
// eg. CommandHelp(service, "foo", "<bar>", "Foo bar baz") will return:
// !foo <bar> - Foo bar baz
// The string is automatatically styled in Discord.
func CommandHelp(service Service, command, arguments, help string) []string {
ticks := ""
if service.Name() == DiscordServiceName {
ticks = "`"
}
if arguments != "" {
return []string{fmt.Sprintf("%s%s%s %s%s - %s", ticks, service.CommandPrefix(), command, arguments, ticks, help)}
}
return []string{fmt.Sprintf("%s%s%s%s - %s", ticks, service.CommandPrefix(), command, ticks, help)}
}
type command struct {
message CommandMessageFunc
help CommandHelpFunc
}
// CommandPlugin is a plugin that can have commands registered and will handle messages matching that command by calling functions.
type CommandPlugin struct {
commands map[string]*command
}
// Name returns the name of the plugin.
func (p *CommandPlugin) Name() string {
return "Command"
}
// Load will load plugin state from a byte array.
func (p *CommandPlugin) Load(bot *Bot, service Service, data []byte) error {
// TODO: Add a generic data store backed by json.
return nil
}
// Save will save plugin state to a byte array.
func (p *CommandPlugin) Save() ([]byte, error) {
// TODO: Add a generic data store backed by json.
return nil, nil
}
// Help returns a list of help strings that are printed when the user requests them.
func (p *CommandPlugin) Help(bot *Bot, service Service, message Message, detailed bool) []string {
if detailed {
return nil
}
help := []string{}
for commandString, command := range p.commands {
if command.help != nil {
arguments, h := command.help(bot, service, message)
help = append(help, CommandHelp(service, commandString, arguments, h)...)
}
}
return help
}
// Message handler.
// Iterates over the registered commands and executes them if the message matches.
func (p *CommandPlugin) Message(bot *Bot, service Service, message Message) {
defer MessageRecover()
if !service.IsMe(message) {
for commandString, command := range p.commands {
if MatchesCommand(service, commandString, message) {
args, parts := ParseCommand(service, message)
command.message(bot, service, message, args, parts)
return
}
}
}
}
// AddCommand adds a command.
func (p *CommandPlugin) AddCommand(commandString string, message CommandMessageFunc, help CommandHelpFunc) {
p.commands[commandString] = &command{
message: message,
help: help,
}
}
// Stats will return the stats for a plugin.
func (p *CommandPlugin) Stats(bot *Bot, service Service, message Message) []string {
return nil
}
// NewCommandPlugin will create a new command plugin.
func NewCommandPlugin() *CommandPlugin {
return &CommandPlugin{make(map[string]*command)}
}