1
2
Fork 0
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:
mat 2023-05-07 02:50:52 -05:00
parent 2823e508b3
commit 53d51a5ca9
8 changed files with 114 additions and 70 deletions

View file

@ -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.

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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,

View file

@ -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)
}

View file

@ -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,

View file

@ -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