1use std::{
2 collections::{BTreeMap, HashMap},
3 fmt::{self, Debug},
4 hash::{Hash, Hasher},
5 ptr,
6 sync::Arc,
7};
8
9use parking_lot::RwLock;
10
11use crate::{
12 builder::{
13 argument_builder::ArgumentBuilderType, literal_argument_builder::Literal,
14 required_argument_builder::Argument,
15 },
16 context::{CommandContext, CommandContextBuilder, ParsedArgument, StringRange},
17 errors::{BuiltInError, CommandSyntaxError},
18 modifier::RedirectModifier,
19 string_reader::StringReader,
20 suggestion::{Suggestions, SuggestionsBuilder},
21};
22
23pub type Command<S> =
24 Option<Arc<dyn Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync>>;
25
26#[non_exhaustive]
28pub struct CommandNode<S> {
29 pub value: ArgumentBuilderType<S>,
30
31 pub children: BTreeMap<String, Arc<RwLock<CommandNode<S>>>>,
33 pub literals: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
34 pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
35
36 pub command: Command<S>,
37 pub requirement: Arc<dyn Fn(&S) -> bool + Send + Sync>,
38 pub redirect: Option<Arc<RwLock<CommandNode<S>>>>,
39 pub forks: bool,
40 pub modifier: Option<Arc<RedirectModifier<S>>>,
41}
42
43impl<S> Clone for CommandNode<S> {
44 fn clone(&self) -> Self {
45 Self {
46 value: self.value.clone(),
47 children: self.children.clone(),
48 literals: self.literals.clone(),
49 arguments: self.arguments.clone(),
50 command: self.command.clone(),
51 requirement: self.requirement.clone(),
52 redirect: self.redirect.clone(),
53 forks: self.forks,
54 modifier: self.modifier.clone(),
55 }
56 }
57}
58
59impl<S> CommandNode<S> {
60 pub fn literal(&self) -> &Literal {
68 match self.value {
69 ArgumentBuilderType::Literal(ref literal) => literal,
70 _ => panic!("CommandNode::literal() called on non-literal node"),
71 }
72 }
73 pub fn argument(&self) -> &Argument<S> {
81 match self.value {
82 ArgumentBuilderType::Argument(ref argument) => argument,
83 _ => panic!("CommandNode::argument() called on non-argument node"),
84 }
85 }
86
87 pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Arc<RwLock<CommandNode<S>>>> {
88 let literals = &self.literals;
89
90 if literals.is_empty() {
91 self.arguments.values().cloned().collect()
92 } else {
93 let cursor = input.cursor();
94 while input.can_read() && input.peek() != ' ' {
95 input.skip();
96 }
97 let text: String = input
98 .string()
99 .chars()
100 .skip(cursor)
101 .take(input.cursor() - cursor)
102 .collect();
103 input.cursor = cursor;
104 let literal = literals.get(&text);
105 if let Some(literal) = literal {
106 vec![literal.clone()]
107 } else {
108 self.arguments.values().cloned().collect()
109 }
110 }
111 }
112
113 pub fn can_use(&self, source: &S) -> bool {
114 (self.requirement)(source)
115 }
116
117 pub fn add_child(&mut self, node: &Arc<RwLock<CommandNode<S>>>) {
118 let child = self.children.get(node.read().name());
119 if let Some(child) = child {
120 if let Some(command) = &node.read().command {
122 child.write().command = Some(command.clone());
123 }
124 for grandchild in node.read().children.values() {
125 child.write().add_child(grandchild);
126 }
127 } else {
128 self.children
129 .insert(node.read().name().to_string(), node.clone());
130 match &node.read().value {
131 ArgumentBuilderType::Literal(literal) => {
132 self.literals.insert(literal.value.clone(), node.clone());
133 }
134 ArgumentBuilderType::Argument(argument) => {
135 self.arguments.insert(argument.name.clone(), node.clone());
136 }
137 }
138 }
139 }
140
141 pub fn name(&self) -> &str {
142 match &self.value {
143 ArgumentBuilderType::Argument(argument) => &argument.name,
144 ArgumentBuilderType::Literal(literal) => &literal.value,
145 }
146 }
147
148 pub fn usage_text(&self) -> String {
149 match &self.value {
150 ArgumentBuilderType::Argument(argument) => format!("<{}>", argument.name),
151 ArgumentBuilderType::Literal(literal) => literal.value.to_owned(),
152 }
153 }
154
155 pub fn child(&self, name: &str) -> Option<Arc<RwLock<CommandNode<S>>>> {
156 self.children.get(name).cloned()
157 }
158
159 pub fn parse_with_context(
160 &self,
161 reader: &mut StringReader,
162 context_builder: &mut CommandContextBuilder<S>,
163 ) -> Result<(), CommandSyntaxError> {
164 match self.value {
165 ArgumentBuilderType::Argument(ref argument) => {
166 let start = reader.cursor();
167 let result = argument.parse(reader)?;
168 let parsed = ParsedArgument {
169 range: StringRange::between(start, reader.cursor()),
170 result,
171 };
172
173 context_builder.with_argument(&argument.name, parsed.clone());
174 context_builder.with_node(Arc::new(RwLock::new(self.clone())), parsed.range);
175
176 Ok(())
177 }
178 ArgumentBuilderType::Literal(ref literal) => {
179 let start = reader.cursor();
180 let end = self.parse(reader);
181
182 if let Some(end) = end {
183 context_builder.with_node(
184 Arc::new(RwLock::new(self.clone())),
185 StringRange::between(start, end),
186 );
187 return Ok(());
188 }
189
190 Err(BuiltInError::LiteralIncorrect {
191 expected: literal.value.clone(),
192 }
193 .create_with_context(reader))
194 }
195 }
196 }
197
198 fn parse(&self, reader: &mut StringReader) -> Option<usize> {
199 match self.value {
200 ArgumentBuilderType::Argument(_) => {
201 panic!("Can't parse argument.")
202 }
203 ArgumentBuilderType::Literal(ref literal) => {
204 let start = reader.cursor();
205 if reader.can_read_length(literal.value.len()) {
206 let end = start + literal.value.len();
207 if reader
208 .string()
209 .get(start..end)
210 .expect("Couldn't slice reader correctly?")
211 == literal.value
212 {
213 reader.cursor = end;
214 if !reader.can_read() || reader.peek() == ' ' {
215 return Some(end);
216 } else {
217 reader.cursor = start;
218 }
219 }
220 }
221 }
222 }
223 None
224 }
225
226 pub fn list_suggestions(
227 &self,
228 context: CommandContext<S>,
229 builder: SuggestionsBuilder,
230 ) -> Suggestions {
231 match &self.value {
232 ArgumentBuilderType::Literal(literal) => {
233 if literal
234 .value
235 .to_lowercase()
236 .starts_with(builder.remaining_lowercase())
237 {
238 builder.suggest(&literal.value).build()
239 } else {
240 Suggestions::default()
241 }
242 }
243 ArgumentBuilderType::Argument(argument) => argument.list_suggestions(context, builder),
244 }
245 }
246}
247
248impl<S> Debug for CommandNode<S> {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 f.debug_struct("CommandNode")
251 .field("children", &self.children)
253 .field("command", &self.command.is_some())
254 .field("redirect", &self.redirect)
256 .field("forks", &self.forks)
257 .finish()
259 }
260}
261
262impl<S> Default for CommandNode<S> {
263 fn default() -> Self {
264 Self {
265 value: ArgumentBuilderType::Literal(Literal::default()),
266
267 children: BTreeMap::new(),
268 literals: HashMap::new(),
269 arguments: HashMap::new(),
270
271 command: None,
272 requirement: Arc::new(|_| true),
273 redirect: None,
274 forks: false,
275 modifier: None,
276 }
277 }
278}
279
280impl<S> Hash for CommandNode<S> {
281 fn hash<H: Hasher>(&self, state: &mut H) {
282 for (k, v) in &self.children {
284 k.hash(state);
285 v.read().hash(state);
286 }
287 ptr::hash(&self.command, state);
289 }
290}
291
292impl<S> PartialEq for CommandNode<S> {
293 fn eq(&self, other: &Self) -> bool {
294 if self.children.len() != other.children.len() {
295 return false;
296 }
297 for (k, v) in &self.children {
298 let other_child = other.children.get(k).unwrap();
299 if !Arc::ptr_eq(v, other_child) {
300 return false;
301 }
302 }
303
304 match &self.command {
305 Some(selfexecutes) => {
306 match &other.command {
308 Some(otherexecutes) =>
309 {
310 #[allow(ambiguous_wide_pointer_comparisons)]
311 if !Arc::ptr_eq(selfexecutes, otherexecutes) {
312 return false;
313 }
314 }
315 _ => {
316 return false;
317 }
318 }
319 }
320 _ => {
321 if other.command.is_some() {
322 return false;
323 }
324 }
325 }
326 true
327 }
328}
329impl<S> Eq for CommandNode<S> {}