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
|
use std::sync::Arc;
use super::Configuration;
use client::Context;
use model::{Message, Permissions};
use std::collections::HashMap;
pub type Check = Fn(&mut Context, &Message, &[String], &Arc<Command>) -> bool + 'static;
pub type Exec = Fn(&mut Context, &Message, Vec<String>, String) -> Result<(), String> + 'static;
pub type Help = Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, &[String])
-> Result<(), String>
+ 'static;
pub type BeforeHook = Fn(&mut Context, &Message, &String) -> bool + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &String, Result<(), String>) + 'static;
pub(crate) type InternalCommand = Arc<Command>;
pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + 'static;
pub enum CommandOrAlias {
Alias(String),
Command(InternalCommand),
}
/// Command function type. Allows to access internal framework things inside
/// your commands.
pub enum CommandType {
StringResponse(String),
Basic(Box<Exec>),
WithCommands(Box<Help>),
}
#[derive(Default)]
pub struct CommandGroup {
pub prefix: Option<String>,
pub commands: HashMap<String, CommandOrAlias>,
}
/// Command struct used to store commands internally.
pub struct Command {
/// A set of checks to be called prior to executing the command. The checks
/// will short-circuit on the first check that returns `false`.
pub checks: Vec<Box<Check>>,
/// Function called when the command is called.
pub exec: CommandType,
/// Ratelimit bucket.
pub bucket: Option<String>,
/// Command description, used by other commands.
pub desc: Option<String>,
/// Example arguments, used by other commands.
pub example: Option<String>,
/// Command usage schema, used by other commands.
pub usage: Option<String>,
/// Whether arguments should be parsed using quote parser or not.
pub use_quotes: bool,
/// Minumum amount of arguments that should be passed.
pub min_args: Option<i32>,
/// Maximum amount of arguments that can be passed.
pub max_args: Option<i32>,
/// Permissions required to use this command.
pub required_permissions: Permissions,
/// Whether command should be displayed in help list or not, used by other commands.
pub help_available: bool,
/// Whether command can be used only privately or not.
pub dm_only: bool,
/// Whether command can be used only in guilds or not.
pub guild_only: bool,
/// Whether command can only be used by owners or not.
pub owners_only: bool,
pub(crate) aliases: Vec<String>,
}
impl Command {
pub fn new<F>(f: F) -> Self
where F: Fn(&mut Context, &Message, Vec<String>, String) -> Result<(), String> + 'static {
Command {
aliases: Vec::new(),
checks: Vec::default(),
exec: CommandType::Basic(Box::new(f)),
desc: None,
usage: None,
example: None,
use_quotes: false,
dm_only: false,
bucket: None,
guild_only: false,
help_available: true,
min_args: None,
max_args: None,
owners_only: false,
required_permissions: Permissions::empty(),
}
}
}
pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
// Find out if they were mentioned. If not, determine if the prefix
// was used. If not, return None.
let mut positions: Vec<usize> = vec![];
if let Some(mention_end) = find_mention_end(&msg.content, conf) {
positions.push(mention_end);
} else if let Some(ref func) = conf.dynamic_prefix {
if let Some(x) = func(ctx, msg) {
if msg.content.starts_with(&x) {
positions.push(x.len());
}
} else {
for n in &conf.prefixes {
if msg.content.starts_with(n) {
positions.push(n.len());
}
}
}
} else {
for n in &conf.prefixes {
if msg.content.starts_with(n) {
positions.push(n.len());
}
}
};
if positions.is_empty() {
return None;
}
if conf.allow_whitespace {
let pos = *unsafe { positions.get_unchecked(0) };
positions.insert(0, pos + 1);
}
Some(positions)
} else if conf.on_mention.is_some() {
find_mention_end(&msg.content, conf).map(|mention_end| {
let mut positions = vec![mention_end];
if conf.allow_whitespace {
positions.insert(0, mention_end + 1);
}
positions
})
} else {
None
}
}
fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
conf.on_mention.as_ref().and_then(|mentions| {
mentions
.iter()
.find(|mention| content.starts_with(&mention[..]))
.map(|m| m.len())
})
}
|