1use std::{
2 cmp::Ordering,
3 collections::{HashMap, HashSet},
4 mem,
5 rc::Rc,
6 sync::Arc,
7};
8
9use parking_lot::RwLock;
10
11use crate::{
12 builder::argument_builder::ArgumentBuilder,
13 context::{CommandContext, CommandContextBuilder},
14 exceptions::{BuiltInExceptions, CommandSyntaxException},
15 parse_results::ParseResults,
16 string_reader::StringReader,
17 suggestion::{Suggestions, SuggestionsBuilder},
18 tree::CommandNode,
19};
20
21pub struct CommandDispatcher<S>
29where
30 Self: Sync + Send,
31{
32 pub root: Arc<RwLock<CommandNode<S>>>,
33}
34
35impl<S> CommandDispatcher<S> {
36 pub fn new() -> Self {
37 Self {
38 root: Arc::new(RwLock::new(CommandNode::default())),
39 }
40 }
41
42 pub fn register(&mut self, node: ArgumentBuilder<S>) -> Arc<RwLock<CommandNode<S>>> {
50 let build = Arc::new(RwLock::new(node.build()));
51 self.root.write().add_child(&build);
52 build
53 }
54
55 pub fn parse(&self, command: StringReader, source: S) -> ParseResults<S> {
56 let source = Arc::new(source);
57
58 let context = CommandContextBuilder::new(self, source, self.root.clone(), command.cursor());
59 self.parse_nodes(&self.root, &command, context).unwrap()
60 }
61
62 fn parse_nodes<'a>(
63 &'a self,
64 node: &Arc<RwLock<CommandNode<S>>>,
65 original_reader: &StringReader,
66 context_so_far: CommandContextBuilder<'a, S>,
67 ) -> Result<ParseResults<'a, S>, CommandSyntaxException> {
68 let source = context_so_far.source.clone();
69 #[allow(clippy::mutable_key_type)] let mut errors = HashMap::<Rc<CommandNode<S>>, CommandSyntaxException>::new();
71 let mut potentials: Vec<ParseResults<S>> = vec![];
72 let cursor = original_reader.cursor();
73
74 for child in node.read().get_relevant_nodes(&mut original_reader.clone()) {
75 if !child.read().can_use(&source) {
76 continue;
77 }
78 let mut context = context_so_far.clone();
79 let mut reader = original_reader.clone();
80
81 let parse_with_context_result =
82 child.read().parse_with_context(&mut reader, &mut context);
83 if let Err(ex) = parse_with_context_result {
84 errors.insert(
85 Rc::new((*child.read()).clone()),
86 BuiltInExceptions::DispatcherParseException {
87 message: ex.message(),
88 }
89 .create_with_context(&reader),
90 );
91 reader.cursor = cursor;
92 continue;
93 }
94 if reader.can_read() && reader.peek() != ' ' {
95 errors.insert(
96 Rc::new((*child.read()).clone()),
97 BuiltInExceptions::DispatcherExpectedArgumentSeparator
98 .create_with_context(&reader),
99 );
100 reader.cursor = cursor;
101 continue;
102 }
103
104 context.with_command(&child.read().command);
105 if reader.can_read_length(if child.read().redirect.is_none() {
106 2
107 } else {
108 1
109 }) {
110 reader.skip();
111 match &child.read().redirect {
112 Some(redirect) => {
113 let child_context = CommandContextBuilder::new(
114 self,
115 source,
116 redirect.clone(),
117 reader.cursor,
118 );
119 let parse = self
120 .parse_nodes(redirect, &reader, child_context)
121 .expect("Parsing nodes failed");
122 context.with_child(Rc::new(parse.context));
123 return Ok(ParseResults {
124 context,
125 reader: parse.reader,
126 exceptions: parse.exceptions,
127 });
128 }
129 _ => {
130 let parse = self
131 .parse_nodes(&child, &reader, context)
132 .expect("Parsing nodes failed");
133 potentials.push(parse);
134 }
135 }
136 } else {
137 potentials.push(ParseResults {
138 context,
139 reader,
140 exceptions: HashMap::new(),
141 });
142 }
143 }
144
145 if !potentials.is_empty() {
146 if potentials.len() > 1 {
147 potentials.sort_by(|a, b| {
148 if !a.reader.can_read() && b.reader.can_read() {
149 return Ordering::Less;
150 };
151 if a.reader.can_read() && !b.reader.can_read() {
152 return Ordering::Greater;
153 };
154 if a.exceptions.is_empty() && !b.exceptions.is_empty() {
155 return Ordering::Less;
156 };
157 if !a.exceptions.is_empty() && b.exceptions.is_empty() {
158 return Ordering::Greater;
159 };
160 Ordering::Equal
161 });
162 }
163 let best_potential = potentials.into_iter().next().unwrap();
164 return Ok(best_potential);
165 }
166
167 Ok(ParseResults {
168 context: context_so_far,
169 reader: original_reader.clone(),
170 exceptions: errors,
171 })
172 }
173
174 pub fn execute(
179 &self,
180 input: impl Into<StringReader>,
181 source: S,
182 ) -> Result<i32, CommandSyntaxException> {
183 let input = input.into();
184
185 let parse = self.parse(input, source);
186 Self::execute_parsed(parse)
187 }
188
189 pub fn add_paths(
190 node: Arc<RwLock<CommandNode<S>>>,
191 result: &mut Vec<Vec<Arc<RwLock<CommandNode<S>>>>>,
192 parents: Vec<Arc<RwLock<CommandNode<S>>>>,
193 ) {
194 let mut current = parents;
195 current.push(node.clone());
196 result.push(current.clone());
197
198 for child in node.read().children.values() {
199 Self::add_paths(child.clone(), result, current.clone());
200 }
201 }
202
203 pub fn get_path(&self, target: CommandNode<S>) -> Vec<String> {
204 let rc_target = Arc::new(RwLock::new(target));
205 let mut nodes: Vec<Vec<Arc<RwLock<CommandNode<S>>>>> = Vec::new();
206 Self::add_paths(self.root.clone(), &mut nodes, vec![]);
207
208 for list in nodes {
209 if *list.last().expect("Nothing in list").read() == *rc_target.read() {
210 let mut result: Vec<String> = Vec::with_capacity(list.len());
211 for node in list {
212 if !Arc::ptr_eq(&node, &self.root) {
213 result.push(node.read().name().to_string());
214 }
215 }
216 return result;
217 }
218 }
219 vec![]
220 }
221
222 pub fn find_node(&self, path: &[&str]) -> Option<Arc<RwLock<CommandNode<S>>>> {
223 let mut node = self.root.clone();
224 for name in path {
225 match node.clone().read().child(name) {
226 Some(child) => {
227 node = child;
228 }
229 _ => {
230 return None;
231 }
232 };
233 }
234 Some(node)
235 }
236
237 pub fn execute_parsed(parse: ParseResults<S>) -> Result<i32, CommandSyntaxException> {
239 if parse.reader.can_read() {
240 if parse.exceptions.len() == 1 {
241 return Err(parse.exceptions.values().next().unwrap().clone());
242 }
243 if parse.context.range.is_empty() {
244 return Err(
245 BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader)
246 );
247 }
248 return Err(
249 BuiltInExceptions::DispatcherUnknownArgument.create_with_context(&parse.reader)
250 );
251 }
252 let mut result = 0i32;
253 let mut successful_forks = 0;
254 let mut forked = false;
255 let mut found_command = false;
256 let command = parse.reader.string();
257 let original = parse.context.build(command);
258 let mut contexts = vec![original];
259 let mut next: Vec<CommandContext<S>> = vec![];
260
261 while !contexts.is_empty() {
262 for context in &contexts {
263 let child = &context.child;
264 if let Some(child) = child {
265 forked |= child.forks;
266 if child.has_nodes() {
267 found_command = true;
268 let modifier = &context.modifier;
269 if let Some(modifier) = modifier {
270 let results = modifier(context);
271 match results {
272 Ok(results) => {
273 if !results.is_empty() {
274 next.extend(
275 results.iter().map(|s| child.copy_for(s.clone())),
276 );
277 }
278 }
279 _ => {
280 if !forked {
283 return Err(results.err().unwrap());
284 }
285 }
286 }
287 } else {
288 next.push(child.copy_for(context.source.clone()));
289 }
290 }
291 } else if let Some(context_command) = &context.command {
292 found_command = true;
293
294 let value = context_command(context);
295 result += value;
296 successful_forks += 1;
298
299 }
302 }
303
304 mem::swap(&mut contexts, &mut next);
306 next.clear();
307 }
308
309 if !found_command {
310 return Err(
312 BuiltInExceptions::DispatcherUnknownCommand.create_with_context(&parse.reader)
313 );
314 }
315
316 Ok(if successful_forks >= 2 {
318 successful_forks
319 } else {
320 result
321 })
322 }
324
325 pub fn get_all_usage(
326 &self,
327 node: &CommandNode<S>,
328 source: &S,
329 restricted: bool,
330 ) -> Vec<String> {
331 let mut result = vec![];
332 self.get_all_usage_recursive(node, source, &mut result, "", restricted);
333 result
334 }
335
336 fn get_all_usage_recursive(
337 &self,
338 node: &CommandNode<S>,
339 source: &S,
340 result: &mut Vec<String>,
341 prefix: &str,
342 restricted: bool,
343 ) {
344 if restricted && !node.can_use(source) {
345 return;
346 }
347 if node.command.is_some() {
348 result.push(prefix.to_owned());
349 }
350 match &node.redirect {
351 Some(redirect) => {
352 let redirect = if redirect.data_ptr() == self.root.data_ptr() {
353 "...".to_string()
354 } else {
355 format!("-> {}", redirect.read().usage_text())
356 };
357 if prefix.is_empty() {
358 result.push(format!("{} {redirect}", node.usage_text()));
359 } else {
360 result.push(format!("{prefix} {redirect}"));
361 }
362 }
363 _ => {
364 for child in node.children.values() {
365 let child = child.read();
366 self.get_all_usage_recursive(
367 &child,
368 source,
369 result,
370 if prefix.is_empty() {
371 child.usage_text()
372 } else {
373 format!("{prefix} {}", child.usage_text())
374 }
375 .as_str(),
376 restricted,
377 );
378 }
379 }
380 }
381 }
382
383 pub fn get_smart_usage(
388 &self,
389 node: &CommandNode<S>,
390 source: &S,
391 ) -> Vec<(Arc<RwLock<CommandNode<S>>>, String)> {
392 let mut result = Vec::new();
393
394 let optional = node.command.is_some();
395 for child in node.children.values() {
396 let usage = self.get_smart_usage_recursive(&child.read(), source, optional, false);
397 if let Some(usage) = usage {
398 result.push((child.clone(), usage));
399 }
400 }
401
402 result
403 }
404
405 fn get_smart_usage_recursive(
406 &self,
407 node: &CommandNode<S>,
408 source: &S,
409 optional: bool,
410 deep: bool,
411 ) -> Option<String> {
412 if !node.can_use(source) {
413 return None;
414 }
415
416 let this = if optional {
417 format!("[{}]", node.usage_text())
418 } else {
419 node.usage_text()
420 };
421 let child_optional = node.command.is_some();
422 let open = if child_optional { "[" } else { "(" };
423 let close = if child_optional { "]" } else { ")" };
424
425 if deep {
426 return Some(this);
427 }
428
429 if let Some(redirect) = &node.redirect {
430 let redirect = if redirect.data_ptr() == self.root.data_ptr() {
431 "...".to_string()
432 } else {
433 format!("-> {}", redirect.read().usage_text())
434 };
435 return Some(format!("{this} {redirect}"));
436 }
437
438 let children = node
439 .children
440 .values()
441 .filter(|child| child.read().can_use(source))
442 .collect::<Vec<_>>();
443 match children.len().cmp(&1) {
444 Ordering::Less => {}
445 Ordering::Equal => {
446 let usage = self.get_smart_usage_recursive(
447 &children[0].read(),
448 source,
449 child_optional,
450 child_optional,
451 );
452 if let Some(usage) = usage {
453 return Some(format!("{this} {usage}"));
454 }
455 }
456 Ordering::Greater => {
457 let mut child_usage = HashSet::new();
458 for child in &children {
459 let usage =
460 self.get_smart_usage_recursive(&child.read(), source, child_optional, true);
461 if let Some(usage) = usage {
462 child_usage.insert(usage);
463 }
464 }
465 match child_usage.len().cmp(&1) {
466 Ordering::Less => {}
467 Ordering::Equal => {
468 let usage = child_usage.into_iter().next().unwrap();
469 let usage = if child_optional {
470 format!("[{}]", usage)
471 } else {
472 usage
473 };
474 return Some(format!("{this} {usage}"));
475 }
476 Ordering::Greater => {
477 let mut builder = String::new();
478 builder.push_str(open);
479 let mut count = 0;
480 for child in children {
481 if count > 0 {
482 builder.push('|');
483 }
484 builder.push_str(&child.read().usage_text());
485 count += 1;
486 }
487 if count > 0 {
488 builder.push_str(close);
489 return Some(format!("{this} {builder}"));
490 }
491 }
492 }
493 }
494 }
495
496 Some(this)
497 }
498
499 pub fn get_completion_suggestions(parse: ParseResults<S>) -> Suggestions {
500 let cursor = parse.reader.total_length();
501 Self::get_completion_suggestions_with_cursor(parse, cursor)
502 }
503
504 pub fn get_completion_suggestions_with_cursor(
505 parse: ParseResults<S>,
506 cursor: usize,
507 ) -> Suggestions {
508 let context = parse.context;
509
510 let node_before_cursor = context.find_suggestion_context(cursor);
511 let parent = node_before_cursor.parent;
512 let start = usize::min(node_before_cursor.start_pos, cursor);
513
514 let full_input = parse.reader.string();
515 let truncated_input = full_input[..cursor].to_string();
516 let truncated_input_lowercase = truncated_input.to_lowercase();
517
518 let mut all_suggestions = Vec::new();
519 for node in parent.read().children.values() {
520 let suggestions = node.read().list_suggestions(
521 context.build(&truncated_input),
522 SuggestionsBuilder::new_with_lowercase(
523 &truncated_input,
524 &truncated_input_lowercase,
525 start,
526 ),
527 );
528 all_suggestions.push(suggestions);
529 }
530
531 Suggestions::merge(full_input, &all_suggestions)
532 }
533}
534
535impl<S> Default for CommandDispatcher<S> {
536 fn default() -> Self {
537 Self::new()
538 }
539}