Skip to content

Commit 38db231

Browse files
committed
brigadier usages
1 parent d5f424b commit 38db231

28 files changed

+757
-102
lines changed

azalea-brigadier/src/builder/argument_builder.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum ArgumentBuilderType {
1616
}
1717

1818
/// A node that hasn't yet been built.
19+
#[derive(Clone)]
1920
pub struct ArgumentBuilder<S> {
2021
arguments: CommandNode<S>,
2122

@@ -134,6 +135,10 @@ impl<S> ArgumentBuilder<S> {
134135
self
135136
}
136137

138+
pub fn arguments(&self) -> &CommandNode<S> {
139+
&self.arguments
140+
}
141+
137142
/// Manually build this node into a [`CommandNode`]. You probably don't need
138143
/// to do this yourself.
139144
pub fn build(self) -> CommandNode<S> {

azalea-brigadier/src/command_dispatcher.rs

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ use crate::{
88
string_reader::StringReader,
99
tree::CommandNode,
1010
};
11-
use std::{cmp::Ordering, collections::HashMap, mem, rc::Rc, sync::Arc};
11+
use std::{
12+
cmp::Ordering,
13+
collections::{HashMap, HashSet},
14+
mem,
15+
rc::Rc,
16+
sync::Arc,
17+
};
1218

1319
/// The root of the command tree. You need to make this to register commands.
1420
///
@@ -297,6 +303,182 @@ impl<S> CommandDispatcher<S> {
297303
})
298304
// Ok(if forked { successful_forks } else { result })
299305
}
306+
307+
pub fn get_all_usage(
308+
&self,
309+
node: &CommandNode<S>,
310+
source: Arc<S>,
311+
restricted: bool,
312+
) -> Vec<String> {
313+
let mut result = vec![];
314+
self.get_all_usage_recursive(node, source, &mut result, "", restricted);
315+
result
316+
}
317+
318+
fn get_all_usage_recursive(
319+
&self,
320+
node: &CommandNode<S>,
321+
source: Arc<S>,
322+
result: &mut Vec<String>,
323+
prefix: &str,
324+
restricted: bool,
325+
) {
326+
if restricted && !node.can_use(source.clone()) {
327+
return;
328+
}
329+
if node.command.is_some() {
330+
result.push(prefix.to_owned());
331+
}
332+
if let Some(redirect) = &node.redirect {
333+
let redirect = if redirect.data_ptr() == self.root.data_ptr() {
334+
"...".to_string()
335+
} else {
336+
format!("-> {}", redirect.read().usage_text())
337+
};
338+
if prefix.is_empty() {
339+
result.push(format!("{} {redirect}", node.usage_text()));
340+
} else {
341+
result.push(format!("{prefix} {redirect}"));
342+
}
343+
} else {
344+
for child in node.children.values() {
345+
let child = child.read();
346+
self.get_all_usage_recursive(
347+
&child,
348+
Arc::clone(&source),
349+
result,
350+
if prefix.is_empty() {
351+
child.usage_text()
352+
} else {
353+
format!("{prefix} {}", child.usage_text())
354+
}
355+
.as_str(),
356+
restricted,
357+
);
358+
}
359+
}
360+
}
361+
362+
/// Gets the possible executable commands from a specified node.
363+
///
364+
/// You may use [`Self::root`] as a target to get usage data for the entire
365+
/// command tree.
366+
pub fn get_smart_usage(
367+
&self,
368+
node: &CommandNode<S>,
369+
source: Arc<S>,
370+
) -> Vec<(Arc<RwLock<CommandNode<S>>>, String)> {
371+
let mut result = Vec::new();
372+
373+
let optional = node.command.is_some();
374+
for child in node.children.values() {
375+
let usage =
376+
self.get_smart_usage_recursive(&child.read(), source.clone(), optional, false);
377+
if let Some(usage) = usage {
378+
result.push((child.clone(), usage));
379+
}
380+
}
381+
382+
result
383+
}
384+
385+
fn get_smart_usage_recursive(
386+
&self,
387+
node: &CommandNode<S>,
388+
source: Arc<S>,
389+
optional: bool,
390+
deep: bool,
391+
) -> Option<String> {
392+
if !node.can_use(source.clone()) {
393+
return None;
394+
}
395+
396+
let this = if optional {
397+
format!("[{}]", node.usage_text())
398+
} else {
399+
node.usage_text()
400+
};
401+
let child_optional = node.command.is_some();
402+
let open = if child_optional { "[" } else { "(" };
403+
let close = if child_optional { "]" } else { ")" };
404+
405+
if deep {
406+
return Some(this);
407+
}
408+
409+
if let Some(redirect) = &node.redirect {
410+
let redirect = if redirect.data_ptr() == self.root.data_ptr() {
411+
"...".to_string()
412+
} else {
413+
format!("-> {}", redirect.read().usage_text())
414+
};
415+
return Some(format!("{this} {redirect}"));
416+
}
417+
418+
let children = node
419+
.children
420+
.values()
421+
.filter(|child| child.read().can_use(source.clone()))
422+
.collect::<Vec<_>>();
423+
match children.len().cmp(&1) {
424+
Ordering::Less => {}
425+
Ordering::Equal => {
426+
let usage = self.get_smart_usage_recursive(
427+
&children[0].read(),
428+
source.clone(),
429+
child_optional,
430+
child_optional,
431+
);
432+
if let Some(usage) = usage {
433+
return Some(format!("{this} {usage}"));
434+
}
435+
}
436+
Ordering::Greater => {
437+
let mut child_usage = HashSet::new();
438+
for child in &children {
439+
let usage = self.get_smart_usage_recursive(
440+
&child.read(),
441+
source.clone(),
442+
child_optional,
443+
true,
444+
);
445+
if let Some(usage) = usage {
446+
child_usage.insert(usage);
447+
}
448+
}
449+
match child_usage.len().cmp(&1) {
450+
Ordering::Less => {}
451+
Ordering::Equal => {
452+
let usage = child_usage.into_iter().next().unwrap();
453+
let usage = if child_optional {
454+
format!("[{}]", usage)
455+
} else {
456+
usage
457+
};
458+
return Some(format!("{this} {usage}"));
459+
}
460+
Ordering::Greater => {
461+
let mut builder = String::new();
462+
builder.push_str(open);
463+
let mut count = 0;
464+
for child in children {
465+
if count > 0 {
466+
builder.push('|');
467+
}
468+
builder.push_str(&child.read().usage_text());
469+
count += 1;
470+
}
471+
if count > 0 {
472+
builder.push_str(close);
473+
return Some(format!("{this} {builder}"));
474+
}
475+
}
476+
}
477+
}
478+
}
479+
480+
Some(this)
481+
}
300482
}
301483

302484
impl<S> Default for CommandDispatcher<S> {

azalea-brigadier/src/context/command_context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl<S> Clone for CommandContext<S> {
3030
command: self.command.clone(),
3131
root_node: self.root_node.clone(),
3232
nodes: self.nodes.clone(),
33-
range: self.range.clone(),
33+
range: self.range,
3434
child: self.child.clone(),
3535
modifier: self.modifier.clone(),
3636
forks: self.forks,
@@ -67,7 +67,7 @@ impl<S> CommandContext<S> {
6767
command: self.command.clone(),
6868
root_node: self.root_node.clone(),
6969
nodes: self.nodes.clone(),
70-
range: self.range.clone(),
70+
range: self.range,
7171
child: self.child.clone(),
7272
modifier: self.modifier.clone(),
7373
forks: self.forks,

azalea-brigadier/src/context/command_context_builder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl<S> Clone for CommandContextBuilder<'_, S> {
3434
source: self.source.clone(),
3535
command: self.command.clone(),
3636
child: self.child.clone(),
37-
range: self.range.clone(),
37+
range: self.range,
3838
modifier: self.modifier.clone(),
3939
forks: self.forks,
4040
}
@@ -77,7 +77,7 @@ impl<'a, S> CommandContextBuilder<'a, S> {
7777
pub fn with_node(&mut self, node: Arc<RwLock<CommandNode<S>>>, range: StringRange) -> &Self {
7878
self.nodes.push(ParsedCommandNode {
7979
node: node.clone(),
80-
range: range.clone(),
80+
range,
8181
});
8282
self.range = StringRange::encompassing(&self.range, &range);
8383
self.modifier = node.read().modifier.clone();
@@ -93,7 +93,7 @@ impl<'a, S> CommandContextBuilder<'a, S> {
9393
source: self.source.clone(),
9494
command: self.command.clone(),
9595
child: self.child.clone().map(|c| Rc::new(c.build(input))),
96-
range: self.range.clone(),
96+
range: self.range,
9797
forks: self.forks,
9898
modifier: self.modifier.clone(),
9999
input: input.to_string(),

azalea-brigadier/src/context/parsed_command_node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl<S> Clone for ParsedCommandNode<S> {
1414
fn clone(&self) -> Self {
1515
Self {
1616
node: self.node.clone(),
17-
range: self.range.clone(),
17+
range: self.range,
1818
}
1919
}
2020
}

azalea-brigadier/src/context/string_range.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cmp;
22

3-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
3+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Copy)]
44
pub struct StringRange {
55
start: usize,
66
end: usize,

0 commit comments

Comments
 (0)