mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-19 14:42:32 +00:00
progress
This commit is contained in:
parent
cb4d871f6f
commit
60b129b3a6
19 changed files with 259 additions and 201 deletions
|
@ -6,27 +6,30 @@ use crate::{
|
|||
suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder},
|
||||
};
|
||||
|
||||
pub enum DefaultArguments {
|
||||
Bool(BoolArgumentType),
|
||||
pub trait Types {
|
||||
fn bool(value: bool) -> Self;
|
||||
}
|
||||
|
||||
/*
|
||||
define_arguments! {
|
||||
#[derive(Types)]
|
||||
enum BrigadierTypes {
|
||||
Entity(EntityArgumentType)
|
||||
}
|
||||
|
||||
===
|
||||
|
||||
enum CustomArguments {
|
||||
enum BrigadierTypes {
|
||||
Bool(BoolArgumentType)
|
||||
|
||||
Entity(EntityArgumentType)
|
||||
}
|
||||
enum BrigadierArguments {
|
||||
BuiltIn(DefaultArguments)
|
||||
Custom(CustomArguments)
|
||||
}
|
||||
*/
|
||||
|
||||
pub trait ArgumentType<T> {
|
||||
pub trait ArgumentType<T>
|
||||
where
|
||||
Self: Sized,
|
||||
T: Types,
|
||||
{
|
||||
// T parse(StringReader reader) throws CommandSyntaxException;
|
||||
|
||||
// default <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
|
||||
|
@ -41,9 +44,12 @@ pub trait ArgumentType<T> {
|
|||
|
||||
fn list_suggestions<S>(
|
||||
&self,
|
||||
context: &CommandContext<S>,
|
||||
context: &CommandContext<S, T>,
|
||||
builder: &mut SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException>;
|
||||
) -> Result<Suggestions, CommandSyntaxException>
|
||||
where
|
||||
S: Sized,
|
||||
T: Sized;
|
||||
|
||||
fn get_examples(&self) -> Vec<String>;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,51 @@
|
|||
use crate::context::command_context::CommandContext;
|
||||
use crate::{
|
||||
context::command_context::CommandContext,
|
||||
exceptions::command_syntax_exception::CommandSyntaxException,
|
||||
string_reader::StringReader,
|
||||
suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder},
|
||||
};
|
||||
|
||||
use super::argument_type::ArgumentType;
|
||||
use super::argument_type::{ArgumentType, Types};
|
||||
|
||||
pub struct BoolArgumentType {}
|
||||
|
||||
impl ArgumentType<bool> for BoolArgumentType {}
|
||||
impl<T> ArgumentType<T> for BoolArgumentType
|
||||
where
|
||||
T: Types,
|
||||
{
|
||||
fn parse(&self, reader: &mut StringReader) -> Result<T, CommandSyntaxException> {
|
||||
Ok(T::bool(reader.read_boolean()?))
|
||||
}
|
||||
|
||||
fn list_suggestions<S>(
|
||||
&self,
|
||||
context: &CommandContext<S, T>,
|
||||
builder: &mut SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException>
|
||||
where
|
||||
S: Sized,
|
||||
T: Sized,
|
||||
{
|
||||
// if ("true".startsWith(builder.getRemainingLowerCase())) {
|
||||
// builder.suggest("true");
|
||||
// }
|
||||
// if ("false".startsWith(builder.getRemainingLowerCase())) {
|
||||
// builder.suggest("false");
|
||||
// }
|
||||
// return builder.buildFuture();
|
||||
if "true".starts_with(builder.get_remaining_lower_case()) {
|
||||
builder.suggest("true");
|
||||
}
|
||||
if "false".starts_with(builder.get_remaining_lower_case()) {
|
||||
builder.suggest("false");
|
||||
}
|
||||
Ok(builder.build_future())
|
||||
}
|
||||
|
||||
fn get_examples(&self) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl BoolArgumentType {
|
||||
const EXAMPLES: &'static [&'static str] = &["true", "false"];
|
||||
|
@ -13,7 +54,7 @@ impl BoolArgumentType {
|
|||
Self {}
|
||||
}
|
||||
|
||||
fn get_bool<S>(context: CommandContext<S>, name: String) {
|
||||
fn get_bool<S, T>(context: CommandContext<S, T>, name: String) {
|
||||
context.get_argument::<bool>(name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,27 +5,25 @@ use crate::{
|
|||
tree::{command_node::CommandNode, root_command_node::RootCommandNode},
|
||||
};
|
||||
|
||||
pub struct BaseArgumentBuilder<S, T>
|
||||
pub struct BaseArgumentBuilder<'a, S, T>
|
||||
where
|
||||
T: ArgumentBuilder<S, T>,
|
||||
S: Sized,
|
||||
T: Sized,
|
||||
{
|
||||
arguments: RootCommandNode<S>,
|
||||
command: Option<dyn Command<S>>,
|
||||
requirement: dyn Fn(&S) -> bool,
|
||||
target: Option<dyn CommandNode<S>>,
|
||||
modifier: Option<dyn RedirectModifier<S>>,
|
||||
arguments: RootCommandNode<'a, S, T>,
|
||||
command: Option<&'a dyn Command<S, T>>,
|
||||
requirement: &'a dyn Fn(&S) -> bool,
|
||||
target: Option<&'a dyn CommandNode<S, T>>,
|
||||
modifier: Option<&'a dyn RedirectModifier<S, T>>,
|
||||
forks: bool,
|
||||
}
|
||||
|
||||
pub trait ArgumentBuilder<S, T> {
|
||||
fn build(self) -> dyn CommandNode<S>;
|
||||
fn build(self) -> dyn CommandNode<S, T>;
|
||||
}
|
||||
|
||||
impl<S, T> BaseArgumentBuilder<S, T>
|
||||
where
|
||||
T: ArgumentBuilder<S, T>,
|
||||
{
|
||||
pub fn then(&mut self, command: dyn CommandNode<S>) -> Result<&mut T, String> {
|
||||
impl<S, T> BaseArgumentBuilder<'_, S, T> {
|
||||
pub fn then(&mut self, command: dyn CommandNode<S, T>) -> Result<&mut T, String> {
|
||||
if self.target.is_some() {
|
||||
return Err("Cannot add children to a redirected node".to_string());
|
||||
}
|
||||
|
@ -33,20 +31,20 @@ where
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn arguments(&self) -> &Vec<dyn CommandNode<S>> {
|
||||
pub fn arguments(&self) -> &Vec<&dyn CommandNode<S, T>> {
|
||||
&self.arguments.get_children()
|
||||
}
|
||||
|
||||
pub fn executes(&mut self, command: dyn Command<S>) -> &mut T {
|
||||
pub fn executes(&mut self, command: dyn Command<S, T>) -> &mut T {
|
||||
self.command = command;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn command(&self) -> dyn Command<S> {
|
||||
pub fn command(&self) -> dyn Command<S, T> {
|
||||
self.command
|
||||
}
|
||||
|
||||
pub fn requires(&mut self, requirement: dyn Fn(&S) -> bool) -> &mut T {
|
||||
pub fn requires(&mut self, requirement: &dyn Fn(&S) -> bool) -> &mut T {
|
||||
self.requirement = requirement;
|
||||
self
|
||||
}
|
||||
|
@ -55,14 +53,14 @@ where
|
|||
self.requirement
|
||||
}
|
||||
|
||||
pub fn redirect(&mut self, target: dyn CommandNode<S>) -> &mut T {
|
||||
pub fn redirect(&mut self, target: &dyn CommandNode<S, T>) -> &mut T {
|
||||
self.forward(target, None, false)
|
||||
}
|
||||
|
||||
pub fn redirect_modifier(
|
||||
&mut self,
|
||||
target: dyn CommandNode<S>,
|
||||
modifier: dyn SingleRedirectModifier<S>,
|
||||
target: &dyn CommandNode<S, T>,
|
||||
modifier: &dyn SingleRedirectModifier<S, T>,
|
||||
) -> &mut T {
|
||||
// forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false);
|
||||
self.forward(target, modifier.map(|m| |o| vec![m.apply(o)]), false)
|
||||
|
@ -70,16 +68,16 @@ where
|
|||
|
||||
pub fn fork(
|
||||
&mut self,
|
||||
target: dyn CommandNode<S>,
|
||||
modifier: dyn RedirectModifier<S>,
|
||||
target: &dyn CommandNode<S, T>,
|
||||
modifier: &dyn RedirectModifier<S, T>,
|
||||
) -> &mut T {
|
||||
self.forward(target, Some(modifier), true)
|
||||
}
|
||||
|
||||
pub fn forward(
|
||||
&mut self,
|
||||
target: dyn CommandNode<S>,
|
||||
modifier: Option<dyn RedirectModifier<S>>,
|
||||
target: &dyn CommandNode<S, T>,
|
||||
modifier: Option<&dyn RedirectModifier<S, T>>,
|
||||
fork: bool,
|
||||
) -> Result<&mut T, String> {
|
||||
if !self.arguments.get_children().is_empty() {
|
||||
|
@ -91,11 +89,11 @@ where
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn get_redirect(&self) -> Option<&dyn CommandNode<S>> {
|
||||
pub fn get_redirect(&self) -> Option<&dyn CommandNode<S, T>> {
|
||||
self.target.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier<S>> {
|
||||
pub fn get_redirect_modifier(&self) -> Option<&dyn RedirectModifier<S, T>> {
|
||||
self.modifier.as_ref()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
use crate::tree::literal_command_node::LiteralCommandNode;
|
||||
|
||||
use super::argument_builder::BaseArgumentBuilder;
|
||||
|
||||
pub struct LiteralArgumentBuilder<'a, S, T> {
|
||||
literal: String,
|
||||
|
||||
pub base: BaseArgumentBuilder<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<'a, S, T> LiteralArgumentBuilder<'a, S, T> {
|
||||
pub fn new(literal: String) -> Self {
|
||||
Self {
|
||||
literal,
|
||||
base: BaseArgumentBuilder::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn literal(name: String) -> Self {
|
||||
Self::new(name)
|
||||
}
|
||||
|
||||
pub fn build(self) -> LiteralCommandNode<'a, S, T> {
|
||||
let result = LiteralCommandNode::new(self.literal, self.base);
|
||||
|
||||
for argument in self.base.arguments {
|
||||
result.add_child(argument);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
|
@ -1,92 +1,50 @@
|
|||
use crate::{
|
||||
arguments::argument_type::ArgumentType,
|
||||
suggestion::suggestion_provider::SuggestionProvider,
|
||||
tree::{argument_command_node::ArgumentCommandNode, command_node::BaseCommandNode},
|
||||
};
|
||||
|
||||
use super::argument_builder::BaseArgumentBuilder;
|
||||
|
||||
// private RequiredArgumentBuilder(final String name, final ArgumentType<T> type) {
|
||||
// this.name = name;
|
||||
// this.type = type;
|
||||
// }
|
||||
|
||||
// public static <S, T> RequiredArgumentBuilder<S, T> argument(final String name, final ArgumentType<T> type) {
|
||||
// return new RequiredArgumentBuilder<>(name, type);
|
||||
// }
|
||||
|
||||
// public RequiredArgumentBuilder<S, T> suggests(final SuggestionProvider<S> provider) {
|
||||
// this.suggestionsProvider = provider;
|
||||
// return getThis();
|
||||
// }
|
||||
|
||||
// public SuggestionProvider<S> getSuggestionsProvider() {
|
||||
// return suggestionsProvider;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// protected RequiredArgumentBuilder<S, T> getThis() {
|
||||
// return this;
|
||||
// }
|
||||
|
||||
// public ArgumentType<T> getType() {
|
||||
// return type;
|
||||
// }
|
||||
|
||||
// public String getName() {
|
||||
// return name;
|
||||
// }
|
||||
|
||||
// public ArgumentCommandNode<S, T> build() {
|
||||
// final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider());
|
||||
|
||||
// for (final CommandNode<S> argument : getArguments()) {
|
||||
// result.addChild(argument);
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
pub struct RequiredArgumentBuilder<S, T> {
|
||||
pub struct RequiredArgumentBuilder<'a, S, T> {
|
||||
// private final String name;
|
||||
// private final ArgumentType<T> type;
|
||||
// private SuggestionProvider<S> suggestionsProvider = null;
|
||||
name: String,
|
||||
type_: dyn ArgumentType<T>,
|
||||
suggestions_provider: Option<dyn SuggestionProvider<S>>,
|
||||
type_: &'a T,
|
||||
suggestions_provider: Option<&'a dyn SuggestionProvider<S, T>>,
|
||||
|
||||
pub base: BaseArgumentBuilder<S, T>,
|
||||
pub base: BaseArgumentBuilder<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<S, T> RequiredArgumentBuilder<S, T> {
|
||||
pub fn new(name: String, type_: dyn ArgumentType<T>) -> Self {
|
||||
impl<'a, S, T> RequiredArgumentBuilder<'a, S, T> {
|
||||
pub fn new(name: String, type_: T) -> Self {
|
||||
Self {
|
||||
name,
|
||||
type_,
|
||||
type_: &type_,
|
||||
suggestions_provider: None,
|
||||
base: BaseArgumentBuilder::new(name, type_),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn argument(name: String, type_: dyn ArgumentType<T>) -> Self {
|
||||
pub fn argument(name: String, type_: T) -> Self {
|
||||
Self::new(name, type_)
|
||||
}
|
||||
|
||||
pub fn suggests(mut self, provider: dyn SuggestionProvider<S>) -> Self {
|
||||
pub fn suggests(mut self, provider: &dyn SuggestionProvider<S, T>) -> Self {
|
||||
self.suggestions_provider = Some(provider);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn suggestions_provider(&self) -> Option<&dyn SuggestionProvider<S>> {
|
||||
pub fn suggestions_provider(&self) -> Option<&dyn SuggestionProvider<S, T>> {
|
||||
self.suggestions_provider.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> &dyn ArgumentType<T> {
|
||||
&self.type_
|
||||
pub fn get_type(&self) -> &T {
|
||||
self.type_
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
self.name
|
||||
}
|
||||
|
||||
// final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider());
|
||||
|
@ -96,7 +54,7 @@ impl<S, T> RequiredArgumentBuilder<S, T> {
|
|||
// }
|
||||
|
||||
// return result;
|
||||
pub fn build(self) -> ArgumentCommandNode<S, T> {
|
||||
pub fn build(self) -> ArgumentCommandNode<'a, S, T> {
|
||||
let result = ArgumentCommandNode {
|
||||
name: self.name,
|
||||
type_: &self.type_,
|
||||
|
|
|
@ -5,6 +5,6 @@ use crate::{
|
|||
|
||||
pub const SINGLE_SUCCESS: i32 = 1;
|
||||
|
||||
pub trait Command<S> {
|
||||
fn run(&self, context: &mut CommandContext<S>) -> Result<i32, CommandSyntaxException>;
|
||||
pub trait Command<S, T> {
|
||||
fn run(&self, context: &mut CommandContext<S, T>) -> Result<i32, CommandSyntaxException>;
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ use crate::tree::root_command_node::RootCommandNode;
|
|||
|
||||
/// The core command dispatcher, for registering, parsing, and executing commands.
|
||||
/// The `S` generic is a custom "source" type, such as a user or originator of a command
|
||||
pub struct CommandDispatcher<S> {
|
||||
root: RootCommandNode<S>,
|
||||
#[derive(Default)]
|
||||
pub struct CommandDispatcher<'a, S, T> {
|
||||
root: RootCommandNode<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<S> CommandDispatcher<S> {
|
||||
impl<S, T> CommandDispatcher<'_, S, T> {
|
||||
/// The string required to separate individual arguments in an input string
|
||||
///
|
||||
/// See: [`ARGUMENT_SEPARATOR_CHAR`]
|
||||
|
@ -22,4 +23,23 @@ impl<S> CommandDispatcher<S> {
|
|||
const USAGE_REQUIRED_OPEN: &'static str = "(";
|
||||
const USAGE_REQUIRED_CLOSE: &'static str = ")";
|
||||
const USAGE_OR: &'static str = "|";
|
||||
|
||||
/// Create a new [`CommandDispatcher`] with the specified root node.
|
||||
/// This is often useful to copy existing or pre-defined command trees.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use azalea_brigadier::{
|
||||
/// command_dispatcher::CommandDispatcher,
|
||||
/// tree::root_command_node::RootCommandNode,
|
||||
/// };
|
||||
///
|
||||
/// let mut dispatcher = CommandDispatcher::new(RootCommandNode::new());
|
||||
/// ```
|
||||
/// # Arguments
|
||||
/// * `root` - the existing [`RootCommandNode`] to use as the basis for this tree
|
||||
/// # Returns
|
||||
/// A new [`CommandDispatcher`] with the specified root node.
|
||||
fn new(root: RootCommandNode<S, T>) -> Self {
|
||||
Self { root }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,27 +3,25 @@ use super::{
|
|||
string_range::StringRange,
|
||||
};
|
||||
use crate::{
|
||||
arguments::argument_type::{ArgumentResult, ArgumentType},
|
||||
command::Command,
|
||||
redirect_modifier::RedirectModifier,
|
||||
arguments::argument_type::ArgumentType, command::Command, redirect_modifier::RedirectModifier,
|
||||
tree::command_node::CommandNode,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct CommandContext<S> {
|
||||
pub struct CommandContext<'a, S, T> {
|
||||
source: S,
|
||||
input: String,
|
||||
command: dyn Command<S>,
|
||||
arguments: HashMap<String, ParsedArgument<dyn ArgumentType<dyn ArgumentResult>>>,
|
||||
root_node: dyn CommandNode<S>,
|
||||
nodes: Vec<ParsedCommandNode<S>>,
|
||||
command: &'a dyn Command<S, T>,
|
||||
arguments: HashMap<String, ParsedArgument<T>>,
|
||||
root_node: &'a dyn CommandNode<S, T>,
|
||||
nodes: Vec<ParsedCommandNode<'a, S, T>>,
|
||||
range: StringRange,
|
||||
child: Option<CommandContext<S>>,
|
||||
modifier: Option<dyn RedirectModifier<S>>,
|
||||
child: Option<CommandContext<'a, S, T>>,
|
||||
modifier: Option<&'a dyn RedirectModifier<S, T>>,
|
||||
forks: bool,
|
||||
}
|
||||
|
||||
impl<S> CommandContext<S> {
|
||||
impl<S, T> CommandContext<'_, S, T> {
|
||||
pub fn clone_for(&self, source: S) -> Self {
|
||||
if self.source == source {
|
||||
return self.clone();
|
||||
|
@ -42,11 +40,11 @@ impl<S> CommandContext<S> {
|
|||
}
|
||||
}
|
||||
|
||||
fn child(&self) -> &Option<CommandContext<S>> {
|
||||
fn child(&self) -> &Option<CommandContext<S, T>> {
|
||||
&self.child
|
||||
}
|
||||
|
||||
fn last_child(&self) -> &CommandContext<S> {
|
||||
fn last_child(&self) -> &CommandContext<S, T> {
|
||||
let mut result = self;
|
||||
while result.child.is_some() {
|
||||
result = result.child.as_ref().unwrap();
|
||||
|
@ -54,7 +52,7 @@ impl<S> CommandContext<S> {
|
|||
result
|
||||
}
|
||||
|
||||
fn command(&self) -> &dyn Command<S> {
|
||||
fn command(&self) -> &dyn Command<S, T> {
|
||||
&self.command
|
||||
}
|
||||
|
||||
|
|
|
@ -25,16 +25,16 @@ use super::{
|
|||
// private boolean forks;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CommandContextBuilder<S> {
|
||||
arguments: HashMap<String, ParsedArgument<dyn ArgumentType<dyn ArgumentResult>>>,
|
||||
root_node: dyn CommandNode<S>,
|
||||
nodes: Vec<ParsedCommandNode<S>>,
|
||||
dispatcher: CommandDispatcher<S>,
|
||||
pub struct CommandContextBuilder<'a, S, T> {
|
||||
arguments: HashMap<String, ParsedArgument<T>>,
|
||||
root_node: &'a dyn CommandNode<S, T>,
|
||||
nodes: Vec<ParsedCommandNode<'a, S, T>>,
|
||||
dispatcher: CommandDispatcher<'a, S, T>,
|
||||
source: S,
|
||||
command: Box<dyn Command<S>>,
|
||||
child: Option<CommandContextBuilder<S>>,
|
||||
command: Box<dyn Command<S, T>>,
|
||||
child: Option<CommandContextBuilder<'a, S, T>>,
|
||||
range: StringRange,
|
||||
modifier: Option<Box<dyn RedirectModifier<S>>>,
|
||||
modifier: Option<Box<dyn RedirectModifier<S, T>>>,
|
||||
forks: bool,
|
||||
}
|
||||
|
||||
|
@ -45,15 +45,15 @@ pub struct CommandContextBuilder<S> {
|
|||
// this.range = StringRange.at(start);
|
||||
// }
|
||||
|
||||
impl<S> CommandContextBuilder<S> {
|
||||
impl<S, T> CommandContextBuilder<'_, S, T> {
|
||||
pub fn new(
|
||||
dispatcher: CommandDispatcher<S>,
|
||||
dispatcher: CommandDispatcher<S, T>,
|
||||
source: S,
|
||||
root_node: dyn CommandNode<S>,
|
||||
root_node: dyn CommandNode<S, T>,
|
||||
start: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
root_node,
|
||||
root_node: &root_node,
|
||||
dispatcher,
|
||||
source,
|
||||
range: StringRange::at(start),
|
||||
|
@ -70,31 +70,25 @@ impl<S> CommandContextBuilder<S> {
|
|||
&self.source
|
||||
}
|
||||
|
||||
pub fn root_node(&self) -> &dyn CommandNode<S> {
|
||||
pub fn root_node(&self) -> &dyn CommandNode<S, T> {
|
||||
&self.root_node
|
||||
}
|
||||
|
||||
pub fn with_argument(
|
||||
mut self,
|
||||
name: String,
|
||||
argument: ParsedArgument<dyn ArgumentType<dyn ArgumentResult>>,
|
||||
) -> Self {
|
||||
pub fn with_argument(mut self, name: String, argument: ParsedArgument<T>) -> Self {
|
||||
self.arguments.insert(name, argument);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn arguments(
|
||||
&self,
|
||||
) -> &HashMap<String, ParsedArgument<dyn ArgumentType<dyn ArgumentResult>>> {
|
||||
pub fn arguments(&self) -> &HashMap<String, ParsedArgument<T>> {
|
||||
&self.arguments
|
||||
}
|
||||
|
||||
pub fn with_command(mut self, command: Box<dyn Command<S>>) -> Self {
|
||||
pub fn with_command(mut self, command: &dyn Command<S, T>) -> Self {
|
||||
self.command = command;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_node(mut self, node: dyn CommandNode<S>, range: StringRange) -> Self {
|
||||
pub fn with_node(mut self, node: dyn CommandNode<S, T>, range: StringRange) -> Self {
|
||||
self.nodes.push(ParsedCommandNode::new(node, range));
|
||||
self.range = StringRange::encompassing(&self.range, &range);
|
||||
self.modifier = node.redirect_modifier();
|
||||
|
@ -102,16 +96,16 @@ impl<S> CommandContextBuilder<S> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_child(mut self, child: CommandContextBuilder<S>) -> Self {
|
||||
pub fn with_child(mut self, child: CommandContextBuilder<S, T>) -> Self {
|
||||
self.child = Some(child);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn child(&self) -> Option<&CommandContextBuilder<S>> {
|
||||
pub fn child(&self) -> Option<&CommandContextBuilder<S, T>> {
|
||||
self.child.as_ref()
|
||||
}
|
||||
|
||||
pub fn last_child(&self) -> Option<&CommandContextBuilder<S>> {
|
||||
pub fn last_child(&self) -> Option<&CommandContextBuilder<S, T>> {
|
||||
let mut result = self;
|
||||
while let Some(child) = result.child() {
|
||||
result = child;
|
||||
|
@ -119,15 +113,15 @@ impl<S> CommandContextBuilder<S> {
|
|||
Some(result)
|
||||
}
|
||||
|
||||
pub fn command(&self) -> &dyn Command<S> {
|
||||
pub fn command(&self) -> &dyn Command<S, T> {
|
||||
&*self.command
|
||||
}
|
||||
|
||||
pub fn nodes(&self) -> &Vec<ParsedCommandNode<S>> {
|
||||
pub fn nodes(&self) -> &Vec<ParsedCommandNode<S, T>> {
|
||||
&self.nodes
|
||||
}
|
||||
|
||||
pub fn build(self, input: &str) -> CommandContext<S> {
|
||||
pub fn build(self, input: &str) -> CommandContext<S, T> {
|
||||
CommandContext {
|
||||
source: self.source,
|
||||
input,
|
||||
|
@ -142,7 +136,7 @@ impl<S> CommandContextBuilder<S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dispatcher(&self) -> &CommandDispatcher<S> {
|
||||
pub fn dispatcher(&self) -> &CommandDispatcher<S, T> {
|
||||
&self.dispatcher
|
||||
}
|
||||
|
||||
|
@ -150,7 +144,7 @@ impl<S> CommandContextBuilder<S> {
|
|||
&self.range
|
||||
}
|
||||
|
||||
pub fn find_suggestion_context(&self, cursor: i32) -> Result<SuggestionContext<S>, String> {
|
||||
pub fn find_suggestion_context(&self, cursor: i32) -> Result<SuggestionContext<S, T>, String> {
|
||||
if self.range.start() <= cursor {
|
||||
if self.range.end() < cursor {
|
||||
if let Some(child) = self.child() {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use super::string_range::StringRange;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct ParsedArgument<T> {
|
||||
range: StringRange,
|
||||
// T is an item in an enum
|
||||
result: T,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,17 @@ use super::string_range::StringRange;
|
|||
use crate::tree::command_node::CommandNode;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
pub struct ParsedCommandNode<S> {
|
||||
node: dyn CommandNode<S>,
|
||||
pub struct ParsedCommandNode<'a, S, T> {
|
||||
node: &'a dyn CommandNode<S, T>,
|
||||
range: StringRange,
|
||||
}
|
||||
|
||||
impl<S> ParsedCommandNode<S> {
|
||||
fn new(node: dyn CommandNode<S>, range: StringRange) -> Self {
|
||||
impl<S, T> ParsedCommandNode<'_, S, T> {
|
||||
fn new(node: &dyn CommandNode<S, T>, range: StringRange) -> Self {
|
||||
Self { node, range }
|
||||
}
|
||||
|
||||
fn node(&self) -> &dyn CommandNode<S> {
|
||||
fn node(&self) -> &dyn CommandNode<S, T> {
|
||||
&self.node
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::tree::command_node::CommandNode;
|
||||
|
||||
pub struct SuggestionContext<S> {
|
||||
parent: dyn CommandNode<S>,
|
||||
pub struct SuggestionContext<'a, S, T> {
|
||||
parent: &'a dyn CommandNode<S, T>,
|
||||
start_pos: usize,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ use crate::{
|
|||
exceptions::command_syntax_exception::CommandSyntaxException,
|
||||
};
|
||||
|
||||
pub trait RedirectModifier<S> {
|
||||
fn apply(&self, context: CommandContext<S>) -> Result<Vec<S>, CommandSyntaxException>;
|
||||
pub trait RedirectModifier<S, T> {
|
||||
fn apply(&self, context: CommandContext<S, T>) -> Result<Vec<S>, CommandSyntaxException>;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ use crate::{
|
|||
exceptions::command_syntax_exception::CommandSyntaxException,
|
||||
};
|
||||
|
||||
pub trait SingleRedirectModifier<S> {
|
||||
fn apply(&self, context: CommandContext<S>) -> Result<S, CommandSyntaxException>;
|
||||
pub trait SingleRedirectModifier<S, T> {
|
||||
fn apply(&self, context: CommandContext<S, T>) -> Result<S, CommandSyntaxException>;
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ use crate::{
|
|||
|
||||
use super::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder};
|
||||
|
||||
pub trait SuggestionProvider<S> {
|
||||
pub trait SuggestionProvider<S, T> {
|
||||
fn suggestions(
|
||||
&self,
|
||||
context: &CommandContext<S>,
|
||||
context: &CommandContext<S, T>,
|
||||
builder: &SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException>;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use crate::{
|
||||
arguments::argument_type::{ArgumentResult, ArgumentType},
|
||||
arguments::argument_type::ArgumentType,
|
||||
builder::required_argument_builder::RequiredArgumentBuilder,
|
||||
context::{
|
||||
command_context::CommandContext, command_context_builder::CommandContextBuilder,
|
||||
|
@ -21,25 +21,25 @@ const USAGE_ARGUMENT_OPEN: &str = "<";
|
|||
const USAGE_ARGUMENT_CLOSE: &str = ">";
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
pub struct ArgumentCommandNode<S, T> {
|
||||
pub struct ArgumentCommandNode<'a, S, T> {
|
||||
name: String,
|
||||
type_: Box<dyn ArgumentType<dyn ArgumentResult>>,
|
||||
custom_suggestions: dyn SuggestionProvider<S>,
|
||||
type_: &'a T,
|
||||
custom_suggestions: &'a dyn SuggestionProvider<S, T>,
|
||||
// Since Rust doesn't have extending, we put the struct this is extending as the "base" field
|
||||
pub base: BaseCommandNode<S>,
|
||||
pub base: BaseCommandNode<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<S, T> ArgumentCommandNode<S, T> {
|
||||
fn get_type(&self) -> &dyn ArgumentType<dyn ArgumentResult> {
|
||||
impl<S, T> ArgumentCommandNode<'_, S, T> {
|
||||
fn get_type(&self) -> &T {
|
||||
&self.type_
|
||||
}
|
||||
|
||||
fn custom_suggestions(&self) -> &dyn SuggestionProvider<S> {
|
||||
fn custom_suggestions(&self) -> &dyn SuggestionProvider<S, T> {
|
||||
&self.custom_suggestions
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T> CommandNode<S> for ArgumentCommandNode<S, T> {
|
||||
impl<S, T> CommandNode<S, T> for ArgumentCommandNode<'_, S, T> {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ impl<S, T> CommandNode<S> for ArgumentCommandNode<S, T> {
|
|||
fn parse(
|
||||
&self,
|
||||
reader: &mut StringReader,
|
||||
context_builder: CommandContextBuilder<S>,
|
||||
context_builder: CommandContextBuilder<S, T>,
|
||||
) -> Result<(), CommandSyntaxException> {
|
||||
// final int start = reader.getCursor();
|
||||
// final T result = type.parse(reader);
|
||||
|
@ -68,7 +68,7 @@ impl<S, T> CommandNode<S> for ArgumentCommandNode<S, T> {
|
|||
|
||||
fn list_suggestions(
|
||||
&self,
|
||||
context: CommandContext<S>,
|
||||
context: CommandContext<S, T>,
|
||||
builder: &mut SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException> {
|
||||
if self.custom_suggestions.is_none() {
|
||||
|
@ -112,7 +112,7 @@ impl<S, T> CommandNode<S> for ArgumentCommandNode<S, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for ArgumentCommandNode<String, String> {
|
||||
impl Display for ArgumentCommandNode<'_, String, String> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "<argument {}: {}>", self.name, self.type_)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
arguments::argument_type::{ArgumentResult, ArgumentType},
|
||||
arguments::argument_type::ArgumentType,
|
||||
builder::argument_builder::ArgumentBuilder,
|
||||
command::Command,
|
||||
context::{command_context::CommandContext, command_context_builder::CommandContextBuilder},
|
||||
|
@ -13,33 +13,33 @@ use crate::{
|
|||
|
||||
use super::{argument_command_node::ArgumentCommandNode, literal_command_node::LiteralCommandNode};
|
||||
|
||||
pub struct BaseCommandNode<S> {
|
||||
children: HashMap<String, dyn CommandNode<S>>,
|
||||
literals: HashMap<String, LiteralCommandNode<S>>,
|
||||
arguments: HashMap<String, ArgumentCommandNode<S, dyn ArgumentType<ArgumentResult>>>,
|
||||
requirement: Option<dyn Fn(&S) -> bool>,
|
||||
redirect: Option<dyn CommandNode<S>>,
|
||||
modifier: Option<dyn RedirectModifier<S>>,
|
||||
pub struct BaseCommandNode<'a, S, T> {
|
||||
children: HashMap<String, &'a dyn CommandNode<S, T>>,
|
||||
literals: HashMap<String, LiteralCommandNode<'a, S, T>>,
|
||||
arguments: HashMap<String, ArgumentCommandNode<'a, S, T>>,
|
||||
requirement: Option<&'a dyn Fn(&S) -> bool>,
|
||||
redirect: Option<&'a dyn CommandNode<S, T>>,
|
||||
modifier: Option<&'a dyn RedirectModifier<S, T>>,
|
||||
forks: bool,
|
||||
command: Option<dyn Command<S>>,
|
||||
command: Option<&'a dyn Command<S, T>>,
|
||||
}
|
||||
|
||||
impl<S> BaseCommandNode<S> {}
|
||||
impl<S, T> BaseCommandNode<'_, S, T> {}
|
||||
|
||||
pub trait CommandNode<S> {
|
||||
pub trait CommandNode<S, T> {
|
||||
fn name(&self) -> &str;
|
||||
fn usage_text(&self) -> &str;
|
||||
fn parse(
|
||||
&self,
|
||||
reader: StringReader,
|
||||
context_builder: CommandContextBuilder<S>,
|
||||
context_builder: CommandContextBuilder<S, T>,
|
||||
) -> Result<(), CommandSyntaxException>;
|
||||
fn list_suggestions(
|
||||
&self,
|
||||
context: CommandContext<S>,
|
||||
context: CommandContext<S, T>,
|
||||
builder: SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException>;
|
||||
fn is_valid_input(&self, input: &str) -> bool;
|
||||
fn create_builder<T>(&self) -> dyn ArgumentBuilder<S, T>;
|
||||
fn create_builder(&self) -> dyn ArgumentBuilder<S, T>;
|
||||
fn get_examples(&self) -> Vec<String>;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use crate::{
|
||||
builder::literal_argument_builder::LiteralArgumentBuilder,
|
||||
command::Command,
|
||||
context::{command_context::CommandContext, command_context_builder::CommandContextBuilder},
|
||||
exceptions::{
|
||||
builtin_exceptions::BuiltInExceptions, command_syntax_exception::CommandSyntaxException,
|
||||
},
|
||||
redirect_modifier::RedirectModifier,
|
||||
string_reader::StringReader,
|
||||
suggestion::{suggestions::Suggestions, suggestions_builder::SuggestionsBuilder},
|
||||
};
|
||||
|
@ -10,14 +13,23 @@ use crate::{
|
|||
use super::command_node::{BaseCommandNode, CommandNode};
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
pub struct LiteralCommandNode<S> {
|
||||
pub struct LiteralCommandNode<'a, S, T> {
|
||||
literal: String,
|
||||
literal_lowercase: String,
|
||||
// Since Rust doesn't have extending, we put the struct this is extending as the "base" field
|
||||
pub base: BaseCommandNode<S>,
|
||||
pub base: BaseCommandNode<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<S> LiteralCommandNode<S> {
|
||||
impl<'a, S, T> LiteralCommandNode<'a, S, T> {
|
||||
pub fn new(literal: String, base: BaseCommandNode<S, T>) -> Self {
|
||||
let literal_lowercase = literal.to_lowercase();
|
||||
Self {
|
||||
literal,
|
||||
literal_lowercase,
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn literal(&self) -> &String {
|
||||
&self.literal
|
||||
}
|
||||
|
@ -39,7 +51,7 @@ impl<S> LiteralCommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S> CommandNode<S> for LiteralCommandNode<S> {
|
||||
impl<S, T> CommandNode<S, T> for LiteralCommandNode<'_, S, T> {
|
||||
fn name(&self) -> &str {
|
||||
&self.literal
|
||||
}
|
||||
|
@ -47,7 +59,7 @@ impl<S> CommandNode<S> for LiteralCommandNode<S> {
|
|||
fn parse(
|
||||
&self,
|
||||
reader: StringReader,
|
||||
context_builder: CommandContextBuilder<S>,
|
||||
context_builder: CommandContextBuilder<S, T>,
|
||||
) -> Result<(), CommandSyntaxException> {
|
||||
let start = reader.get_cursor();
|
||||
let end = self.parse(reader);
|
||||
|
@ -63,7 +75,7 @@ impl<S> CommandNode<S> for LiteralCommandNode<S> {
|
|||
|
||||
fn list_suggestions(
|
||||
&self,
|
||||
context: CommandContext<S>,
|
||||
context: CommandContext<S, T>,
|
||||
builder: SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException> {
|
||||
if self
|
||||
|
@ -84,7 +96,7 @@ impl<S> CommandNode<S> for LiteralCommandNode<S> {
|
|||
self.literal
|
||||
}
|
||||
|
||||
fn create_builder(&self) -> LiteralArgumentBuilder<S> {
|
||||
fn create_builder(&self) -> LiteralArgumentBuilder<S, T> {
|
||||
let builder = LiteralArgumentBuilder::literal(self.literal());
|
||||
builder.requires(self.requirement());
|
||||
builder.forward(self.redirect(), self.redirect_modifier(), self.is_fork());
|
||||
|
|
|
@ -12,12 +12,12 @@ use crate::{
|
|||
use super::command_node::{BaseCommandNode, CommandNode};
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
pub struct RootCommandNode<S> {
|
||||
pub struct RootCommandNode<'a, S, T> {
|
||||
// Since Rust doesn't have extending, we put the struct this is extending as the "base" field
|
||||
pub base: BaseCommandNode<S>,
|
||||
pub base: BaseCommandNode<'a, S, T>,
|
||||
}
|
||||
|
||||
impl<S> CommandNode<S> for RootCommandNode<S> {
|
||||
impl<S, T> CommandNode<S, T> for RootCommandNode<'_, S, T> {
|
||||
fn name(&self) -> &str {
|
||||
""
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ impl<S> CommandNode<S> for RootCommandNode<S> {
|
|||
fn parse(
|
||||
&self,
|
||||
reader: StringReader,
|
||||
context_builder: CommandContextBuilder<S>,
|
||||
context_builder: CommandContextBuilder<S, T>,
|
||||
) -> Result<(), CommandSyntaxException> {
|
||||
}
|
||||
|
||||
fn list_suggestions(
|
||||
&self,
|
||||
context: CommandContext<S>,
|
||||
context: CommandContext<S, T>,
|
||||
builder: SuggestionsBuilder,
|
||||
) -> Result<Suggestions, CommandSyntaxException> {
|
||||
Suggestions::empty()
|
||||
|
@ -54,7 +54,7 @@ impl<S> CommandNode<S> for RootCommandNode<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for RootCommandNode<()> {
|
||||
impl<S, T> Display for RootCommandNode<'_, S, T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "<root>")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue