Skip to content

Commit 3ba1e65

Browse files
committed
Add support for optional arguments
1 parent 60eb4c6 commit 3ba1e65

File tree

2 files changed

+151
-82
lines changed

2 files changed

+151
-82
lines changed

src/commands.rs

Lines changed: 116 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::state_machine::{CharacterSet, StateMachine};
22
use reqwest::blocking::Client as HttpClient;
33
use serenity::{model::channel::Message, prelude::Context};
4-
use std::collections::HashMap;
4+
use std::{collections::HashMap, sync::Arc};
55

66
const PREFIX: &'static str = "?";
77
pub(crate) type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
8-
pub(crate) type CmdPtr = Box<dyn for<'m> Fn(Args<'m>) -> Result<()> + Send + Sync>;
8+
pub(crate) type CmdPtr = Arc<dyn for<'m> Fn(Args<'m>) -> Result<()> + Send + Sync>;
99

1010
pub struct Args<'m> {
1111
pub http: &'m HttpClient,
@@ -35,45 +35,71 @@ impl Commands {
3535
handler: impl Fn(Args) -> Result<()> + Send + Sync + 'static,
3636
) {
3737
info!("Adding command {}", &command);
38-
let mut param_names = Vec::new();
3938
let mut state = 0;
4039

40+
let mut opt_lambda_state: Option<usize> = None;
41+
let mut opt_final_states = vec![];
42+
4143
command
4244
.split(' ')
4345
.filter(|segment| segment.len() > 0)
4446
.enumerate()
4547
.for_each(|(i, segment)| {
46-
if segment.starts_with("```\n") && segment.ends_with("```") {
47-
state = add_space(&mut self.state_machine, state, i);
48-
state = add_code_segment_multi_line(&mut self.state_machine, state);
49-
param_names.push(&segment[4..segment.len() - 3]);
50-
} else if segment.starts_with("```") && segment.ends_with("```") {
51-
state = add_space(&mut self.state_machine, state, i);
52-
state = add_code_segment_single_line_long(&mut self.state_machine, state);
53-
param_names.push(&segment[3..segment.len() - 3]);
54-
} else if segment.starts_with("`") && segment.ends_with("`") {
55-
state = add_space(&mut self.state_machine, state, i);
56-
state = add_code_segment_single_line_short(&mut self.state_machine, state);
57-
param_names.push(&segment[1..segment.len() - 1]);
58-
} else if segment.starts_with("{") && segment.ends_with("}") {
59-
state = add_space(&mut self.state_machine, state, i);
60-
state = add_dynamic_segment(&mut self.state_machine, state);
61-
param_names.push(&segment[1..segment.len() - 1]);
62-
} else if segment.ends_with("...") {
63-
state = add_space(&mut self.state_machine, state, i);
64-
state = add_remaining_segment(&mut self.state_machine, state);
65-
param_names.push(&segment[..segment.len() - 3]);
48+
if let Some(name) = key_value_pair(segment) {
49+
if let Some(lambda) = opt_lambda_state {
50+
state = add_key_value(&name, &mut self.state_machine, lambda);
51+
self.state_machine.add_next_state(state, lambda);
52+
opt_final_states.push(state);
53+
} else {
54+
opt_final_states.push(state);
55+
state = add_space(&mut self.state_machine, state, i);
56+
opt_lambda_state = Some(state);
57+
state = add_key_value(&name, &mut self.state_machine, state);
58+
self.state_machine
59+
.add_next_state(state, opt_lambda_state.unwrap());
60+
opt_final_states.push(state);
61+
}
6662
} else {
63+
opt_lambda_state = None;
64+
opt_final_states.truncate(0);
6765
state = add_space(&mut self.state_machine, state, i);
68-
segment.chars().for_each(|ch| {
69-
state = self.state_machine.add(state, CharacterSet::from_char(ch))
70-
});
66+
67+
if segment.starts_with("```\n") && segment.ends_with("```") {
68+
let name = &segment[4..segment.len() - 3];
69+
state = add_code_segment_multi_line(name, &mut self.state_machine, state);
70+
} else if segment.starts_with("```") && segment.ends_with("```") {
71+
let name = &segment[3..segment.len() - 3];
72+
state = add_code_segment_single_line_long(name, &mut self.state_machine, state);
73+
} else if segment.starts_with("`") && segment.ends_with("`") {
74+
let name = &segment[1..segment.len() - 1];
75+
state =
76+
add_code_segment_single_line_short(name, &mut self.state_machine, state);
77+
} else if segment.starts_with("{") && segment.ends_with("}") {
78+
let name = &segment[1..segment.len() - 1];
79+
state = add_dynamic_segment(name, &mut self.state_machine, state);
80+
} else if segment.ends_with("...") {
81+
let name = &segment[..segment.len() - 3];
82+
state = add_remaining_segment(name, &mut self.state_machine, state);
83+
} else {
84+
segment.chars().for_each(|ch| {
85+
state = self.state_machine.add(state, CharacterSet::from_char(ch))
86+
});
87+
}
7188
}
7289
});
7390

74-
self.state_machine.set_final_state(state);
75-
self.state_machine.set_handler(state, Box::new(handler));
76-
self.state_machine.set_param_names(state, param_names);
91+
let handler = Arc::new(handler);
92+
93+
if opt_lambda_state.is_some() {
94+
opt_final_states.iter().for_each(|state| {
95+
self.state_machine.set_final_state(*state);
96+
self.state_machine.set_handler(*state, handler.clone());
97+
});
98+
} else {
99+
self.state_machine.set_final_state(state);
100+
self.state_machine.set_handler(state, handler.clone());
101+
}
102+
77103
self.menu.as_mut().map(|menu| {
78104
*menu += command;
79105
*menu += "\n"
@@ -104,7 +130,20 @@ impl Commands {
104130
}
105131
}
106132

107-
#[inline]
133+
fn key_value_pair(s: &'static str) -> Option<&'static str> {
134+
s.match_indices("={}")
135+
.nth(0)
136+
.map(|pair| {
137+
let name = &s[0..pair.0];
138+
if name.len() > 0 {
139+
Some(name)
140+
} else {
141+
None
142+
}
143+
})
144+
.flatten()
145+
}
146+
108147
fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> usize {
109148
if i > 0 {
110149
let mut char_set = CharacterSet::from_char(' ');
@@ -116,31 +155,40 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
116155
state
117156
}
118157

119-
#[inline]
120-
fn add_dynamic_segment(state_machine: &mut StateMachine, mut state: usize) -> usize {
158+
fn add_dynamic_segment(
159+
name: &'static str,
160+
state_machine: &mut StateMachine,
161+
mut state: usize,
162+
) -> usize {
121163
let mut char_set = CharacterSet::any();
122164
char_set.remove(' ');
123165
state = state_machine.add(state, char_set);
124166
state_machine.add_next_state(state, state);
125-
state_machine.start_parse(state);
167+
state_machine.start_parse(state, name);
126168
state_machine.end_parse(state);
127169

128170
state
129171
}
130172

131-
#[inline]
132-
fn add_remaining_segment(state_machine: &mut StateMachine, mut state: usize) -> usize {
173+
fn add_remaining_segment(
174+
name: &'static str,
175+
state_machine: &mut StateMachine,
176+
mut state: usize,
177+
) -> usize {
133178
let char_set = CharacterSet::any();
134179
state = state_machine.add(state, char_set);
135180
state_machine.add_next_state(state, state);
136-
state_machine.start_parse(state);
181+
state_machine.start_parse(state, name);
137182
state_machine.end_parse(state);
138183

139184
state
140185
}
141186

142-
#[inline]
143-
fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usize) -> usize {
187+
fn add_code_segment_multi_line(
188+
name: &'static str,
189+
state_machine: &mut StateMachine,
190+
mut state: usize,
191+
) -> usize {
144192
state = state_machine.add(state, CharacterSet::from_char('`'));
145193
state = state_machine.add(state, CharacterSet::from_char('`'));
146194
state = state_machine.add(state, CharacterSet::from_char('`'));
@@ -160,7 +208,7 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
160208

161209
state = state_machine.add(state, CharacterSet::any());
162210
state_machine.add_next_state(state, state);
163-
state_machine.start_parse(state);
211+
state_machine.start_parse(state, name);
164212
state_machine.end_parse(state);
165213

166214
state = state_machine.add(state, CharacterSet::from_char('`'));
@@ -170,14 +218,17 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
170218
state
171219
}
172220

173-
#[inline]
174-
fn add_code_segment_single_line_long(state_machine: &mut StateMachine, mut state: usize) -> usize {
221+
fn add_code_segment_single_line_long(
222+
name: &'static str,
223+
state_machine: &mut StateMachine,
224+
mut state: usize,
225+
) -> usize {
175226
state = state_machine.add(state, CharacterSet::from_char('`'));
176227
state = state_machine.add(state, CharacterSet::from_char('`'));
177228
state = state_machine.add(state, CharacterSet::from_char('`'));
178229
state = state_machine.add(state, CharacterSet::any());
179230
state_machine.add_next_state(state, state);
180-
state_machine.start_parse(state);
231+
state_machine.start_parse(state, name);
181232
state_machine.end_parse(state);
182233
state = state_machine.add(state, CharacterSet::from_char('`'));
183234
state = state_machine.add(state, CharacterSet::from_char('`'));
@@ -186,14 +237,34 @@ fn add_code_segment_single_line_long(state_machine: &mut StateMachine, mut state
186237
state
187238
}
188239

189-
#[inline]
190-
fn add_code_segment_single_line_short(state_machine: &mut StateMachine, mut state: usize) -> usize {
240+
fn add_code_segment_single_line_short(
241+
name: &'static str,
242+
state_machine: &mut StateMachine,
243+
mut state: usize,
244+
) -> usize {
191245
state = state_machine.add(state, CharacterSet::from_char('`'));
192246
state = state_machine.add(state, CharacterSet::any());
193247
state_machine.add_next_state(state, state);
194-
state_machine.start_parse(state);
248+
state_machine.start_parse(state, name);
195249
state_machine.end_parse(state);
196250
state = state_machine.add(state, CharacterSet::from_char('`'));
197251

198252
state
199253
}
254+
255+
fn add_key_value(name: &'static str, state_machine: &mut StateMachine, mut state: usize) -> usize {
256+
name.chars().for_each(|c| {
257+
state = state_machine.add(state, CharacterSet::from_char(c));
258+
});
259+
state = state_machine.add(state, CharacterSet::from_char('='));
260+
261+
let mut char_set = CharacterSet::any();
262+
char_set.remove(' ');
263+
char_set.remove('\n');
264+
state = state_machine.add(state, char_set);
265+
state_machine.add_next_state(state, state);
266+
state_machine.start_parse(state, name);
267+
state_machine.end_parse(state);
268+
269+
state
270+
}

0 commit comments

Comments
 (0)