diff options
| author | mat <github@matdoes.dev> | 2022-01-09 22:33:45 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-01-09 22:33:45 -0600 |
| commit | 315f2258190b33c63df7797a97178019f5aea02b (patch) | |
| tree | 1ec5f467e7bd42f7aed3aaadbcbc226f8a6ce4f2 /azalea-brigadier/src/context | |
| parent | d56f60c05f316ab4cc37ebe7a9ad4caf91a75de6 (diff) | |
| download | azalea-drasl-315f2258190b33c63df7797a97178019f5aea02b.tar.xz | |
add some more stuff from brigadier
Diffstat (limited to 'azalea-brigadier/src/context')
| -rw-r--r-- | azalea-brigadier/src/context/command_context.rs | 87 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/command_context_builder.rs | 180 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/parsed_argument.rs | 24 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/parsed_command_node.rs | 22 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/string_range.rs | 45 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/suggestion_context.rs | 6 |
6 files changed, 364 insertions, 0 deletions
diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index ddbb447e..c6210a88 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -1,3 +1,90 @@ +use super::{ + parsed_argument::ParsedArgument, parsed_command_node::ParsedCommandNode, + string_range::StringRange, +}; +use crate::{ + arguments::argument_type::ArgumentType, command::Command, redirect_modifier::RedirectModifier, + tree::command_node::CommandNode, +}; +use std::collections::HashMap; + pub struct CommandContext<S> { source: S, + input: String, + command: dyn Command<S>, + arguments: HashMap<String, ParsedArgument<S, dyn ArgumentType>>, + root_node: dyn CommandNode<S>, + nodes: Vec<ParsedCommandNode<S>>, + range: StringRange, + child: Option<CommandContext<S>>, + modifier: Option<dyn RedirectModifier<S>>, + forks: bool, +} + +impl<S> CommandContext<S> { + pub fn clone_for(&self, source: S) -> Self { + if self.source == source { + return self.clone(); + } + Self { + source, + input: self.input.clone(), + command: self.command.clone(), + arguments: self.arguments.clone(), + root_node: self.root_node.clone(), + nodes: self.nodes.clone(), + range: self.range.clone(), + child: self.child.clone(), + modifier: self.modifier.clone(), + forks: self.forks, + } + } + + fn child(&self) -> &Option<CommandContext<S>> { + &self.child + } + + fn last_child(&self) -> &CommandContext<S> { + let mut result = self; + while result.child.is_some() { + result = result.child.as_ref().unwrap(); + } + result + } + + fn command(&self) -> &dyn Command<S> { + &self.command + } + + fn source(&self) -> &S { + &self.source + } + + // public <V> V getArgument(final String name, final Class<V> clazz) { + // final ParsedArgument<S, ?> argument = arguments.get(name); + + // if (argument == null) { + // throw new IllegalArgumentException("No such argument '" + name + "' exists on this command"); + // } + + // final Object result = argument.getResult(); + // if (PRIMITIVE_TO_WRAPPER.getOrDefault(clazz, clazz).isAssignableFrom(result.getClass())) { + // return (V) result; + // } else { + // throw new IllegalArgumentException("Argument '" + name + "' is defined as " + result.getClass().getSimpleName() + ", not " + clazz); + // } + // } + fn get_argument<V>(&self, name: &str) -> Result<V, String> { + let argument = self.arguments.get(name); + + if argument.is_none() { + return Err(format!( + "No such argument '{}' exists on this command", + name + )); + } + + let result = argument.unwrap().result(); + Ok(result) + } } diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index e69de29b..e74b5b1c 100644 --- a/azalea-brigadier/src/context/command_context_builder.rs +++ b/azalea-brigadier/src/context/command_context_builder.rs @@ -0,0 +1,180 @@ +use std::collections::HashMap; + +use crate::{ + arguments::argument_type::ArgumentType, command::Command, + command_dispatcher::CommandDispatcher, redirect_modifier::RedirectModifier, + tree::command_node::CommandNode, +}; + +use super::{ + command_context::CommandContext, parsed_argument::ParsedArgument, + parsed_command_node::ParsedCommandNode, string_range::StringRange, + suggestion_context::SuggestionContext, +}; + +// public class CommandContextBuilder<S> { +// private final Map<String, ParsedArgument<S, ?>> arguments = new LinkedHashMap<>(); +// private final CommandNode<S> rootNode; +// private final List<ParsedCommandNode<S>> nodes = new ArrayList<>(); +// private final CommandDispatcher<S> dispatcher; +// private S source; +// private Command<S> command; +// private CommandContextBuilder<S> child; +// private StringRange range; +// private RedirectModifier<S> modifier = null; +// private boolean forks; + +#[derive(Clone)] +pub struct CommandContextBuilder<S> { + arguments: HashMap<String, ParsedArgument<S, dyn ArgumentType>>, + root_node: dyn CommandNode<S>, + nodes: Vec<ParsedCommandNode<S>>, + dispatcher: CommandDispatcher<S>, + source: S, + command: Box<dyn Command<S>>, + child: Option<CommandContextBuilder<S>>, + range: StringRange, + modifier: Option<Box<dyn RedirectModifier<S>>>, + forks: bool, +} + +// public CommandContextBuilder(final CommandDispatcher<S> dispatcher, final S source, final CommandNode<S> rootNode, final int start) { +// this.rootNode = rootNode; +// this.dispatcher = dispatcher; +// this.source = source; +// this.range = StringRange.at(start); +// } + +impl<S> CommandContextBuilder<S> { + pub fn new( + dispatcher: CommandDispatcher<S>, + source: S, + root_node: dyn CommandNode<S>, + start: usize, + ) -> Self { + Self { + root_node, + dispatcher, + source, + range: StringRange::at(start), + ..Default::default() + } + } + + pub fn with_source(mut self, source: S) -> Self { + self.source = source; + self + } + + pub fn source(&self) -> &S { + &self.source + } + + pub fn root_node(&self) -> &dyn CommandNode<S> { + &self.root_node + } + + pub fn with_argument( + mut self, + name: String, + argument: ParsedArgument<S, dyn ArgumentType>, + ) -> Self { + self.arguments.insert(name, argument); + self + } + + pub fn arguments(&self) -> &HashMap<String, ParsedArgument<S, dyn ArgumentType>> { + &self.arguments + } + + pub fn with_command(mut self, command: Box<dyn Command<S>>) -> Self { + self.command = command; + self + } + + pub fn with_node(mut self, node: dyn CommandNode<S>, range: StringRange) -> Self { + self.nodes.push(ParsedCommandNode::new(node, range)); + self.range = StringRange::encompassing(&self.range, &range); + self.modifier = node.redirect_modifier(); + self.forks = node.is_fork(); + self + } + + pub fn with_child(mut self, child: CommandContextBuilder<S>) -> Self { + self.child = Some(child); + self + } + + pub fn child(&self) -> Option<&CommandContextBuilder<S>> { + self.child.as_ref() + } + + pub fn last_child(&self) -> Option<&CommandContextBuilder<S>> { + let mut result = self; + while let Some(child) = result.child() { + result = child; + } + Some(result) + } + + pub fn command(&self) -> &dyn Command<S> { + &*self.command + } + + pub fn nodes(&self) -> &Vec<ParsedCommandNode<S>> { + &self.nodes + } + + pub fn build(self, input: &str) -> CommandContext<S> { + CommandContext { + source: self.source, + input, + arguments: self.arguments, + command: self.command, + root_node: self.root_node, + nodes: self.nodes, + range: self.range, + child: self.child.map(|child| child.build(input)), + modifier: self.modifier, + forks: self.forks, + } + } + + pub fn dispatcher(&self) -> &CommandDispatcher<S> { + &self.dispatcher + } + + pub fn range(&self) -> &StringRange { + &self.range + } + + pub fn find_suggestion_context(&self, cursor: i32) -> Result<SuggestionContext<S>, String> { + if self.range.start() <= cursor { + if self.range.end() < cursor { + if let Some(child) = self.child() { + child.find_suggestion_context(cursor); + } else if !self.nodes.is_empty() { + let last = self.nodes.last().unwrap(); + let end = last.range().end() + 1; + return SuggestionContext::new(last.node(), end); + } else { + return SuggestionContext::new(self.root_node, self.range.start()); + } + } else { + let prev = self.root_node; + for node in &self.nodes { + let node_range = node.range(); + if node_range.start() <= cursor && cursor <= node_range.end() { + return SuggestionContext::new(prev, node_range.start()); + } + prev = node.node(); + } + if prev.is_none() { + return Err(String::from("Can't find node before cursor")); + } + return SuggestionContext::new(prev.unwrap(), self.range.start()); + } + } + Err(String::from("Can't find node before cursor")) + } +} diff --git a/azalea-brigadier/src/context/parsed_argument.rs b/azalea-brigadier/src/context/parsed_argument.rs index e69de29b..5f9c2cdb 100644 --- a/azalea-brigadier/src/context/parsed_argument.rs +++ b/azalea-brigadier/src/context/parsed_argument.rs @@ -0,0 +1,24 @@ +use super::string_range::StringRange; + +#[derive(PartialEq, Eq, Hash)] +pub struct ParsedArgument<S, T> { + range: StringRange, + result: T, +} + +impl<S, T> ParsedArgument<S, T> { + fn new(start: usize, end: usize, result: T) -> Self { + Self { + range: StringRange::between(start, end), + result, + } + } + + fn range(&self) -> &StringRange { + &self.range + } + + fn result(&self) -> &T { + &self.result + } +} diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs index e69de29b..98e99959 100644 --- a/azalea-brigadier/src/context/parsed_command_node.rs +++ b/azalea-brigadier/src/context/parsed_command_node.rs @@ -0,0 +1,22 @@ +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>, + range: StringRange, +} + +impl<S> ParsedCommandNode<S> { + fn new(node: dyn CommandNode<S>, range: StringRange) -> Self { + Self { node, range } + } + + fn node(&self) -> &dyn CommandNode<S> { + &self.node + } + + fn range(&self) -> &StringRange { + &self.range + } +} diff --git a/azalea-brigadier/src/context/string_range.rs b/azalea-brigadier/src/context/string_range.rs index e69de29b..d775ab68 100644 --- a/azalea-brigadier/src/context/string_range.rs +++ b/azalea-brigadier/src/context/string_range.rs @@ -0,0 +1,45 @@ +use std::cmp; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StringRange { + start: usize, + end: usize, +} + +impl StringRange { + pub fn new(start: usize, end: usize) -> Self { + Self { start, end } + } + + pub fn at(pos: usize) -> Self { + Self::new(pos, pos) + } + + pub fn between(start: usize, end: usize) -> Self { + Self::new(start, end) + } + + pub fn encompassing(a: &Self, b: &Self) -> Self { + Self::new(cmp::min(a.start, b.start), cmp::max(a.end, b.end)) + } + + pub fn start(&self) -> usize { + self.start + } + + pub fn end(&self) -> usize { + self.end + } + + pub fn get(&self, reader: &str) -> &str { + &reader[self.start..self.end] + } + + pub fn is_empty(&self) -> bool { + self.start == self.end + } + + pub fn length(&self) -> usize { + self.end - self.start + } +} diff --git a/azalea-brigadier/src/context/suggestion_context.rs b/azalea-brigadier/src/context/suggestion_context.rs index e69de29b..540a5f23 100644 --- a/azalea-brigadier/src/context/suggestion_context.rs +++ b/azalea-brigadier/src/context/suggestion_context.rs @@ -0,0 +1,6 @@ +use crate::tree::command_node::CommandNode; + +pub struct SuggestionContext<S> { + parent: dyn CommandNode<S>, + start_pos: usize, +} |
