mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
more brigadier docs
This commit is contained in:
parent
2823e508b3
commit
53d51a5ca9
8 changed files with 114 additions and 70 deletions
|
@ -4,4 +4,23 @@ A Rust port of Mojang's [Brigadier](https://github.com/Mojang/brigadier) command
|
|||
|
||||
# Examples
|
||||
|
||||
See the [tests](https://github.com/mat-1/azalea/tree/main/azalea-brigadier/tests).
|
||||
```rust
|
||||
use azalea_brigadier::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct CommandSource {}
|
||||
|
||||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").executes(|_| 42));
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("foo", Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
```
|
||||
|
||||
See the [tests](https://github.com/mat-1/azalea/tree/main/azalea-brigadier/tests) for more.
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ impl ArgumentType for Double {
|
|||
pub fn double() -> impl ArgumentType {
|
||||
Double::default()
|
||||
}
|
||||
pub fn get_integer<S>(context: &CommandContext<S>, name: &str) -> Option<f64> {
|
||||
pub fn get_double<S>(context: &CommandContext<S>, name: &str) -> Option<f64> {
|
||||
context
|
||||
.argument(name)
|
||||
.unwrap()
|
||||
|
|
|
@ -45,7 +45,7 @@ impl ArgumentType for Float {
|
|||
pub fn float() -> impl ArgumentType {
|
||||
Float::default()
|
||||
}
|
||||
pub fn get_integer<S>(context: &CommandContext<S>, name: &str) -> Option<f32> {
|
||||
pub fn get_float<S>(context: &CommandContext<S>, name: &str) -> Option<f32> {
|
||||
context
|
||||
.argument(name)
|
||||
.unwrap()
|
||||
|
|
|
@ -45,7 +45,7 @@ impl ArgumentType for Long {
|
|||
pub fn long() -> impl ArgumentType {
|
||||
Long::default()
|
||||
}
|
||||
pub fn get_integer<S>(context: &CommandContext<S>, name: &str) -> Option<i64> {
|
||||
pub fn get_long<S>(context: &CommandContext<S>, name: &str) -> Option<i64> {
|
||||
context
|
||||
.argument(name)
|
||||
.unwrap()
|
||||
|
|
|
@ -43,15 +43,38 @@ impl<S> ArgumentBuilder<S> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Continue building this node with a child node.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea_brigadier::prelude::*;
|
||||
/// # let mut subject = CommandDispatcher::<()>::new();
|
||||
/// literal("foo").then(
|
||||
/// literal("bar").executes(|ctx: &CommandContext<()>| 42)
|
||||
/// )
|
||||
/// # ;
|
||||
/// ```
|
||||
pub fn then(self, argument: ArgumentBuilder<S>) -> Self {
|
||||
self.then_built(argument.build())
|
||||
}
|
||||
|
||||
/// Add an already built child node to this node.
|
||||
///
|
||||
/// You should usually use [`Self::then`] instead.
|
||||
pub fn then_built(mut self, argument: CommandNode<S>) -> Self {
|
||||
self.arguments.add_child(&Arc::new(RwLock::new(argument)));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the command to be executed when this node is reached. If this is not
|
||||
/// present on a node, it is not a valid command.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea_brigadier::prelude::*;
|
||||
/// # let mut subject = CommandDispatcher::<()>::new();
|
||||
/// # subject.register(
|
||||
/// literal("foo").executes(|ctx: &CommandContext<()>| 42)
|
||||
/// # );
|
||||
/// ```
|
||||
pub fn executes<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: Fn(&CommandContext<S>) -> i32 + Send + Sync + 'static,
|
||||
|
@ -60,6 +83,22 @@ impl<S> ArgumentBuilder<S> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the requirement for this node to be considered. If this is not
|
||||
/// present on a node, it is considered to always pass.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea_brigadier::prelude::*;
|
||||
/// # use std::sync::Arc;
|
||||
/// # pub struct CommandSource {
|
||||
/// # pub opped: bool,
|
||||
/// # }
|
||||
/// # let mut subject = CommandDispatcher::<CommandSource>::new();
|
||||
/// # subject.register(
|
||||
/// literal("foo")
|
||||
/// .requires(|s: Arc<CommandSource>| s.opped)
|
||||
/// // ...
|
||||
/// # .executes(|ctx: &CommandContext<CommandSource>| 42)
|
||||
/// # );
|
||||
pub fn requires<F>(mut self, requirement: F) -> Self
|
||||
where
|
||||
F: Fn(Arc<S>) -> bool + Send + Sync + 'static,
|
||||
|
@ -95,6 +134,8 @@ impl<S> ArgumentBuilder<S> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Manually build this node into a [`CommandNode`]. You probably don't need
|
||||
/// to do this yourself.
|
||||
pub fn build(self) -> CommandNode<S> {
|
||||
let mut result = CommandNode {
|
||||
value: self.arguments.value,
|
||||
|
|
|
@ -11,6 +11,12 @@ use crate::{
|
|||
use std::{cmp::Ordering, collections::HashMap, mem, rc::Rc, sync::Arc};
|
||||
|
||||
/// The root of the command tree. You need to make this to register commands.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea_brigadier::prelude::*;
|
||||
/// # struct CommandSource;
|
||||
/// let mut subject = CommandDispatcher::<CommandSource>::new();
|
||||
/// ```
|
||||
pub struct CommandDispatcher<S>
|
||||
where
|
||||
Self: Sync + Send,
|
||||
|
@ -25,13 +31,22 @@ impl<S> CommandDispatcher<S> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Add a new node to the root.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea_brigadier::prelude::*;
|
||||
/// # let mut subject = CommandDispatcher::<()>::new();
|
||||
/// subject.register(literal("foo").executes(|_| 42));
|
||||
/// ```
|
||||
pub fn register(&mut self, node: ArgumentBuilder<S>) -> Arc<RwLock<CommandNode<S>>> {
|
||||
let build = Arc::new(RwLock::new(node.build()));
|
||||
self.root.write().add_child(&build);
|
||||
build
|
||||
}
|
||||
|
||||
pub fn parse(&self, command: StringReader, source: Arc<S>) -> ParseResults<S> {
|
||||
pub fn parse(&self, command: StringReader, source: S) -> ParseResults<S> {
|
||||
let source = Arc::new(source);
|
||||
|
||||
let context = CommandContextBuilder::new(self, source, self.root.clone(), command.cursor());
|
||||
self.parse_nodes(&self.root, &command, context).unwrap()
|
||||
}
|
||||
|
@ -140,11 +155,17 @@ impl<S> CommandDispatcher<S> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse and execute the command using the given input and context. The
|
||||
/// number returned depends on the command, and may not be of significance.
|
||||
///
|
||||
/// This is a shortcut for `Self::parse` and `Self::execute_parsed`.
|
||||
pub fn execute(
|
||||
&self,
|
||||
input: StringReader,
|
||||
source: Arc<S>,
|
||||
input: impl Into<StringReader>,
|
||||
source: S,
|
||||
) -> Result<i32, CommandSyntaxException> {
|
||||
let input = input.into();
|
||||
|
||||
let parse = self.parse(input, source);
|
||||
Self::execute_parsed(parse)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,11 @@ pub mod tree;
|
|||
pub mod prelude {
|
||||
pub use crate::{
|
||||
arguments::{
|
||||
double_argument_type::double, float_argument_type::float,
|
||||
integer_argument_type::integer, long_argument_type::long, string_argument_type::string,
|
||||
double_argument_type::{double, get_double},
|
||||
float_argument_type::{float, get_float},
|
||||
integer_argument_type::{get_integer, integer},
|
||||
long_argument_type::{get_long, long},
|
||||
string_argument_type::{get_string, greedy_string, string, word},
|
||||
},
|
||||
builder::{literal_argument_builder::literal, required_argument_builder::argument},
|
||||
command_dispatcher::CommandDispatcher,
|
||||
|
|
|
@ -18,19 +18,6 @@ fn input_with_offset(input: &str, offset: usize) -> StringReader {
|
|||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_execute_command() {
|
||||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").executes(|_| 42));
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("foo".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_execute_offset_command() {
|
||||
let mut subject = CommandDispatcher::new();
|
||||
|
@ -38,7 +25,7 @@ fn create_and_execute_offset_command() {
|
|||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute(input_with_offset("/foo", 1), Arc::new(CommandSource {}))
|
||||
.execute(input_with_offset("/foo", 1), &CommandSource {})
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
|
@ -50,18 +37,8 @@ fn create_and_merge_commands() {
|
|||
subject.register(literal("base").then(literal("foo").executes(|_| 42)));
|
||||
subject.register(literal("base").then(literal("bar").executes(|_| 42)));
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("base foo".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("base bar".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
assert_eq!(subject.execute("base foo", &CommandSource {}).unwrap(), 42);
|
||||
assert_eq!(subject.execute("base bar", &CommandSource {}).unwrap(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -70,7 +47,7 @@ fn execute_unknown_command() {
|
|||
subject.register(literal("bar"));
|
||||
subject.register(literal("baz"));
|
||||
|
||||
let execute_result = subject.execute("foo".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("foo", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -85,7 +62,7 @@ fn execute_impermissible_command() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").requires(|_| false));
|
||||
|
||||
let execute_result = subject.execute("foo".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("foo", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -100,7 +77,7 @@ fn execute_empty_command() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal(""));
|
||||
|
||||
let execute_result = subject.execute("".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -115,7 +92,7 @@ fn execute_unknown_subcommand() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").executes(|_| 42));
|
||||
|
||||
let execute_result = subject.execute("foo bar".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("foo bar", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -130,7 +107,7 @@ fn execute_incorrect_literal() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").executes(|_| 42).then(literal("bar")));
|
||||
|
||||
let execute_result = subject.execute("foo baz".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("foo baz", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -150,7 +127,7 @@ fn execute_ambiguous_incorrect_argument() {
|
|||
.then(literal("baz")),
|
||||
);
|
||||
|
||||
let execute_result = subject.execute("foo unknown".into(), Arc::new(CommandSource {}));
|
||||
let execute_result = subject.execute("foo unknown", &CommandSource {});
|
||||
|
||||
let err = execute_result.err().unwrap();
|
||||
match err.type_ {
|
||||
|
@ -172,12 +149,7 @@ fn execute_subcommand() {
|
|||
.executes(|_| 42),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("foo =".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
100
|
||||
);
|
||||
assert_eq!(subject.execute("foo =", &CommandSource {}).unwrap(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -185,7 +157,7 @@ fn parse_incomplete_literal() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").then(literal("bar").executes(|_| 42)));
|
||||
|
||||
let parse = subject.parse("foo ".into(), Arc::new(CommandSource {}));
|
||||
let parse = subject.parse("foo ".into(), &CommandSource {});
|
||||
assert_eq!(parse.reader.remaining(), " ");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
}
|
||||
|
@ -195,7 +167,7 @@ fn parse_incomplete_argument() {
|
|||
let mut subject = CommandDispatcher::new();
|
||||
subject.register(literal("foo").then(argument("bar", integer()).executes(|_| 42)));
|
||||
|
||||
let parse = subject.parse("foo ".into(), Arc::new(CommandSource {}));
|
||||
let parse = subject.parse("foo ".into(), &CommandSource {});
|
||||
assert_eq!(parse.reader.remaining(), " ");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
}
|
||||
|
@ -210,12 +182,7 @@ fn execute_ambiguious_parent_subcommand() {
|
|||
.then(argument("right", integer()).then(argument("sub", integer()).executes(|_| 100))),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("test 1 2".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
100
|
||||
);
|
||||
assert_eq!(subject.execute("test 1 2", &CommandSource {}).unwrap(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -231,9 +198,7 @@ fn execute_ambiguious_parent_subcommand_via_redirect() {
|
|||
subject.register(literal("redirect").redirect(real));
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("redirect 1 2".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
subject.execute("redirect 1 2", &CommandSource {}).unwrap(),
|
||||
100
|
||||
);
|
||||
}
|
||||
|
@ -248,7 +213,7 @@ fn execute_redirected_multiple_times() {
|
|||
|
||||
let input = "redirected redirected actual";
|
||||
|
||||
let parse = subject.parse(input.into(), Arc::new(CommandSource {}));
|
||||
let parse = subject.parse(input.into(), &CommandSource {});
|
||||
assert_eq!(parse.context.range.get(input), "redirected");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
assert_eq!(*parse.context.root.read(), *root.read());
|
||||
|
@ -299,7 +264,7 @@ fn execute_redirected() {
|
|||
subject.register(literal("redirected").fork(subject.root.clone(), Arc::new(modifier)));
|
||||
|
||||
let input = "redirected actual";
|
||||
let parse = subject.parse(input.into(), Arc::new(CommandSource {}));
|
||||
let parse = subject.parse(input.into(), CommandSource {});
|
||||
assert_eq!(parse.context.range.get(input), "redirected");
|
||||
assert_eq!(parse.context.nodes.len(), 1);
|
||||
assert_eq!(*parse.context.root.read(), *subject.root.read());
|
||||
|
@ -314,7 +279,7 @@ fn execute_redirected() {
|
|||
assert_eq!(*parse.context.root.read(), *subject.root.read());
|
||||
assert_eq!(parent.nodes[0].range, parent.range);
|
||||
assert_eq!(*parent.nodes[0].node.read(), *concrete_node.read());
|
||||
assert_eq!(parent.source, Arc::new(CommandSource {}));
|
||||
assert_eq!(*parent.source, CommandSource {});
|
||||
|
||||
assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2);
|
||||
}
|
||||
|
@ -329,7 +294,7 @@ fn execute_orphaned_subcommand() {
|
|||
.executes(|_| 42),
|
||||
);
|
||||
|
||||
let result = subject.execute("foo 5".into(), Arc::new(CommandSource {}));
|
||||
let result = subject.execute("foo 5", &CommandSource {});
|
||||
assert!(result.is_err());
|
||||
let result = result.unwrap_err();
|
||||
assert_eq!(
|
||||
|
@ -346,12 +311,7 @@ fn execute_invalid_other() {
|
|||
subject.register(literal("w").executes(|_| panic!("This should not run")));
|
||||
subject.register(literal("world").executes(|_| 42));
|
||||
|
||||
assert_eq!(
|
||||
subject
|
||||
.execute("world".into(), Arc::new(CommandSource {}))
|
||||
.unwrap(),
|
||||
42
|
||||
);
|
||||
assert_eq!(subject.execute("world", &CommandSource {}).unwrap(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -364,7 +324,7 @@ fn parse_no_space_separator() {
|
|||
.executes(|_| 42),
|
||||
);
|
||||
|
||||
let result = subject.execute("foo$".into(), Arc::new(CommandSource {}));
|
||||
let result = subject.execute("foo$", &CommandSource {});
|
||||
assert!(result.is_err());
|
||||
let result = result.unwrap_err();
|
||||
assert_eq!(
|
||||
|
@ -384,7 +344,7 @@ fn execute_invalid_subcommand() {
|
|||
.executes(|_| 42),
|
||||
);
|
||||
|
||||
let result = subject.execute("foo bar".into(), Arc::new(CommandSource {}));
|
||||
let result = subject.execute("foo bar", &CommandSource {});
|
||||
assert!(result.is_err());
|
||||
let result = result.unwrap_err();
|
||||
// this fails for some reason, i blame mojang
|
||||
|
|
Loading…
Add table
Reference in a new issue