diff options
| author | mat <github@matdoes.dev> | 2022-01-11 00:01:47 -0600 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-01-11 00:01:47 -0600 |
| commit | cc4fe62fc82842e0bde628437a45d55c6a82f1f3 (patch) | |
| tree | 9248cb03406681f81d6d29a0878220fbe1e836e2 /azalea-brigadier/src | |
| parent | 60b129b3a62b66dd389d1775892405fe735b9540 (diff) | |
| download | azalea-drasl-cc4fe62fc82842e0bde628437a45d55c6a82f1f3.tar.xz | |
adfsfasdfaSDQAWERTERYTUYghyubnjnrdfxcv etgvbhy0ujn-
Diffstat (limited to 'azalea-brigadier/src')
| -rw-r--r-- | azalea-brigadier/src/arguments/argument_type.rs | 6 | ||||
| -rw-r--r-- | azalea-brigadier/src/arguments/bool_argument_type.rs | 6 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/command_context.rs | 11 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/command_context_builder.rs | 2 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/parsed_argument.rs | 2 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/parsed_command_node.rs | 9 | ||||
| -rw-r--r-- | azalea-brigadier/src/context/string_range.rs | 2 | ||||
| -rw-r--r-- | azalea-brigadier/src/message.rs | 1 | ||||
| -rw-r--r-- | azalea-brigadier/src/suggestion/suggestion.rs | 90 | ||||
| -rw-r--r-- | azalea-brigadier/src/suggestion/suggestions.rs | 58 | ||||
| -rw-r--r-- | azalea-brigadier/src/suggestion/suggestions_builder.rs | 115 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/argument_command_node.rs | 23 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/command_node.rs | 2 | ||||
| -rw-r--r-- | azalea-brigadier/src/tree/root_command_node.rs | 1 |
14 files changed, 299 insertions, 29 deletions
diff --git a/azalea-brigadier/src/arguments/argument_type.rs b/azalea-brigadier/src/arguments/argument_type.rs index 107b1cbf..46026735 100644 --- a/azalea-brigadier/src/arguments/argument_type.rs +++ b/azalea-brigadier/src/arguments/argument_type.rs @@ -7,7 +7,9 @@ use crate::{ }; pub trait Types { - fn bool(value: bool) -> Self; + fn bool(value: bool) -> Self + where + Self: Sized; } /* @@ -28,7 +30,7 @@ enum BrigadierTypes { pub trait ArgumentType<T> where Self: Sized, - T: Types, + T: Types + ?Sized, { // T parse(StringReader reader) throws CommandSyntaxException; diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs index dc2c6896..1237caa0 100644 --- a/azalea-brigadier/src/arguments/bool_argument_type.rs +++ b/azalea-brigadier/src/arguments/bool_argument_type.rs @@ -33,13 +33,13 @@ where // builder.suggest("false"); // } // return builder.buildFuture(); - if "true".starts_with(builder.get_remaining_lower_case()) { + if "true".starts_with(builder.remaining_lowercase()) { builder.suggest("true"); } - if "false".starts_with(builder.get_remaining_lower_case()) { + if "false".starts_with(builder.remaining_lowercase()) { builder.suggest("false"); } - Ok(builder.build_future()) + Ok(builder.build()) } fn get_examples(&self) -> Vec<String> { diff --git a/azalea-brigadier/src/context/command_context.rs b/azalea-brigadier/src/context/command_context.rs index 36741906..68144a40 100644 --- a/azalea-brigadier/src/context/command_context.rs +++ b/azalea-brigadier/src/context/command_context.rs @@ -14,17 +14,20 @@ pub struct CommandContext<'a, S, T> { command: &'a dyn Command<S, T>, arguments: HashMap<String, ParsedArgument<T>>, root_node: &'a dyn CommandNode<S, T>, - nodes: Vec<ParsedCommandNode<'a, S, T>>, + nodes: Vec<ParsedCommandNode<S, T>>, range: StringRange, - child: Option<CommandContext<'a, S, T>>, + child: Option<&'a CommandContext<'a, S, T>>, modifier: Option<&'a dyn RedirectModifier<S, T>>, forks: bool, } -impl<S, T> CommandContext<'_, S, T> { +impl<S, T> CommandContext<'_, S, T> +where + S: PartialEq, +{ pub fn clone_for(&self, source: S) -> Self { if self.source == source { - return self.clone(); + return *self; } Self { source, diff --git a/azalea-brigadier/src/context/command_context_builder.rs b/azalea-brigadier/src/context/command_context_builder.rs index 878d7692..88e26343 100644 --- a/azalea-brigadier/src/context/command_context_builder.rs +++ b/azalea-brigadier/src/context/command_context_builder.rs @@ -28,7 +28,7 @@ use super::{ pub struct CommandContextBuilder<'a, S, T> { arguments: HashMap<String, ParsedArgument<T>>, root_node: &'a dyn CommandNode<S, T>, - nodes: Vec<ParsedCommandNode<'a, S, T>>, + nodes: Vec<ParsedCommandNode<S, T>>, dispatcher: CommandDispatcher<'a, S, T>, source: S, command: Box<dyn Command<S, T>>, diff --git a/azalea-brigadier/src/context/parsed_argument.rs b/azalea-brigadier/src/context/parsed_argument.rs index 75c07784..447a1223 100644 --- a/azalea-brigadier/src/context/parsed_argument.rs +++ b/azalea-brigadier/src/context/parsed_argument.rs @@ -1,6 +1,6 @@ use super::string_range::StringRange; -#[derive(PartialEq, Eq, Hash)] +#[derive(PartialEq, Eq, Hash, Clone)] pub struct ParsedArgument<T> { range: StringRange, // T is an item in an enum diff --git a/azalea-brigadier/src/context/parsed_command_node.rs b/azalea-brigadier/src/context/parsed_command_node.rs index a006aa4b..14168a06 100644 --- a/azalea-brigadier/src/context/parsed_command_node.rs +++ b/azalea-brigadier/src/context/parsed_command_node.rs @@ -1,14 +1,13 @@ use super::string_range::StringRange; use crate::tree::command_node::CommandNode; -#[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct ParsedCommandNode<'a, S, T> { - node: &'a dyn CommandNode<S, T>, +pub struct ParsedCommandNode<S, T> { + node: Box<dyn CommandNode<S, T>>, range: StringRange, } -impl<S, T> ParsedCommandNode<'_, S, T> { - fn new(node: &dyn CommandNode<S, T>, range: StringRange) -> Self { +impl<S, T> ParsedCommandNode<S, T> { + fn new(node: dyn CommandNode<S, T>, range: StringRange) -> Self { Self { node, range } } diff --git a/azalea-brigadier/src/context/string_range.rs b/azalea-brigadier/src/context/string_range.rs index d775ab68..87098a1a 100644 --- a/azalea-brigadier/src/context/string_range.rs +++ b/azalea-brigadier/src/context/string_range.rs @@ -1,6 +1,6 @@ use std::cmp; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StringRange { start: usize, end: usize, diff --git a/azalea-brigadier/src/message.rs b/azalea-brigadier/src/message.rs index 71d0b178..42894d0e 100644 --- a/azalea-brigadier/src/message.rs +++ b/azalea-brigadier/src/message.rs @@ -1,5 +1,6 @@ use std::rc::Rc; +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Message(Rc<String>); impl Message { diff --git a/azalea-brigadier/src/suggestion/suggestion.rs b/azalea-brigadier/src/suggestion/suggestion.rs index e69de29b..4cbed7be 100644 --- a/azalea-brigadier/src/suggestion/suggestion.rs +++ b/azalea-brigadier/src/suggestion/suggestion.rs @@ -0,0 +1,90 @@ +use std::cmp; + +use crate::{context::string_range::StringRange, message::Message}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Suggestion { + range: StringRange, + text: String, + tooltip: Option<Message>, +} + +impl Suggestion { + pub fn new(range: StringRange, text: String) -> Suggestion { + Suggestion { + range, + text, + tooltip: None, + } + } + + pub fn new_with_tooltip(range: StringRange, text: String, tooltip: Message) -> Suggestion { + Suggestion { + range, + text, + tooltip: Some(tooltip), + } + } + + pub fn range(&self) -> &StringRange { + &self.range + } + + pub fn text(&self) -> &String { + &self.text + } + + pub fn tooltip(&self) -> Option<&Message> { + self.tooltip.as_ref() + } + + pub fn apply(&self, input: &str) -> String { + if self.range.start() == 0 && self.range.end() == input.len() { + return self.text.clone(); + } + let mut result = String::new(); + if self.range.start() > 0 { + result.push_str(&input[0..self.range.start()]); + } + result.push_str(&self.text); + if self.range.end() < input.len() { + result.push_str(&input[self.range.end()..]); + } + result + } + + pub fn expand(&self, command: &str, range: StringRange) -> Suggestion { + if range == self.range { + return self.clone(); + } + let mut result = String::new(); + if range.start() < self.range.start() { + result.push_str(&command[range.start()..self.range.start()]); + } + result.push_str(&self.text); + if range.end() > self.range.end() { + result.push_str(&command[self.range.end()..range.end()]); + } + Suggestion { + range, + text: result, + tooltip: self.tooltip.clone(), + } + } + + pub fn compare_ignore_case(&self, b: &Suggestion) -> cmp::Ordering { + self.text.to_lowercase().cmp(&b.text.to_lowercase()) + } +} + +impl PartialOrd for Suggestion { + fn partial_cmp(&self, other: &Suggestion) -> Option<cmp::Ordering> { + Some(self.text.cmp(&other.text)) + } +} + +impl Ord for Suggestion { + fn cmp(&self, other: &Suggestion) -> cmp::Ordering { + self.text.cmp(&other.text) + } +} diff --git a/azalea-brigadier/src/suggestion/suggestions.rs b/azalea-brigadier/src/suggestion/suggestions.rs index 354fc418..18572d20 100644 --- a/azalea-brigadier/src/suggestion/suggestions.rs +++ b/azalea-brigadier/src/suggestion/suggestions.rs @@ -1 +1,59 @@ +use std::cmp; + +use crate::{context::string_range::StringRange, message::Message}; + pub struct Suggestions {} + +// #[cfg(test)] +// mod tests { +// use crate::suggestion::suggestion::Suggestion; + +// use super::*; + +// #[test] +// fn merge_empty() { +// let merged = Suggestions::merge("foo b", vec![]); +// assert_eq!(merged.is_empty(), true); +// } + +// #[test] +// fn merge_single() { +// let suggestions = Suggestions::new(StringRange::at(5), "ar".to_string()); +// let merged = Suggestions::merge("foo b", vec![suggestions]); +// assert_eq!(merged, suggestions); +// } + +// #[test] +// fn merge_multiple() { +// let a = Suggestions::new( +// StringRange::at(5), +// vec![ +// Suggestion::new(StringRange::at(5), "ar".to_string()), +// Suggestion::new(StringRange::at(5), "az".to_string()), +// Suggestion::new(StringRange::at(5), "Az".to_string()), +// ], +// ); +// let b = Suggestions::new( +// StringRange::between(4, 5), +// vec![ +// Suggestion::new(StringRange::between(4, 5), "foo".to_string()), +// Suggestion::new(StringRange::between(4, 5), "qux".to_string()), +// Suggestion::new(StringRange::between(4, 5), "apple".to_string()), +// Suggestion::new(StringRange::between(4, 5), "Bar".to_string()), +// ], +// ); +// let merged = Suggestions::merge("foo b", vec![a, b]); +// assert_eq!( +// merged.get_list(), +// vec![ +// Suggestion::new(StringRange::between(4, 5), "apple".to_string()), +// Suggestion::new(StringRange::between(4, 5), "bar".to_string()), +// Suggestion::new(StringRange::between(4, 5), "Bar".to_string()), +// Suggestion::new(StringRange::between(4, 5), "baz".to_string()), +// Suggestion::new(StringRange::between(4, 5), "bAz".to_string()), +// Suggestion::new(StringRange::between(4, 5), "foo".to_string()), +// Suggestion::new(StringRange::between(4, 5), "qux".to_string()), +// ] +// ); +// } +// } diff --git a/azalea-brigadier/src/suggestion/suggestions_builder.rs b/azalea-brigadier/src/suggestion/suggestions_builder.rs index 6960f52b..7853a3a2 100644 --- a/azalea-brigadier/src/suggestion/suggestions_builder.rs +++ b/azalea-brigadier/src/suggestion/suggestions_builder.rs @@ -1 +1,114 @@ -pub struct SuggestionsBuilder {} +use crate::context::string_range::StringRange; + +use super::{suggestion::Suggestion, suggestions::Suggestions}; + +pub struct SuggestionsBuilder { + input: String, + input_lowercase: String, + start: usize, + remaining: String, + remaining_lowercase: String, + result: Vec<Suggestion>, +} + +impl SuggestionsBuilder { + pub fn new_with_lowercase( + input: String, + input_lowercase: String, + start: usize, + ) -> SuggestionsBuilder { + SuggestionsBuilder { + input, + input_lowercase, + start, + remaining: input.get(start..).unwrap().to_string(), + remaining_lowercase: input_lowercase.get(start..).unwrap().to_string(), + result: Vec::new(), + } + } + + pub fn new(input: String, start: usize) -> SuggestionsBuilder { + SuggestionsBuilder::new_with_lowercase(input, input.to_lowercase(), start) + } + + pub fn input(&self) -> &str { + &self.input + } + + pub fn start(&self) -> usize { + self.start + } + + pub fn remaining(&self) -> &str { + &self.remaining + } + + pub fn remaining_lowercase(&self) -> &str { + &self.remaining_lowercase + } + + pub fn build(&self) -> Suggestions { + Suggestions::create(self.input(), self.result) + } + + pub fn suggest(&mut self, text: &str) -> &mut SuggestionsBuilder { + if text == self.remaining { + return self; + } + self.result.push(Suggestion::new( + StringRange::between(self.start, self.input.len()), + text, + )); + self + } + + pub fn suggest_with_tooltip(&mut self, text: &str, tooltip: &str) -> &mut SuggestionsBuilder { + if text == self.remaining { + return self; + } + self.result.push(Suggestion::new_with_tooltip( + StringRange::between(self.start, self.input.len()), + text, + tooltip, + )); + self + } + + pub fn suggest_with_value(&mut self, value: i32) -> &mut SuggestionsBuilder { + self.result.push(IntegerSuggestion::new( + StringRange::between(self.start, self.input.len()), + value, + )); + self + } + + pub fn suggest_with_value_and_tooltip( + &mut self, + value: i32, + tooltip: &str, + ) -> &mut SuggestionsBuilder { + self.result.push(IntegerSuggestion::new_with_tooltip( + StringRange::between(self.start, self.input.len()), + value, + tooltip, + )); + self + } + + pub fn add(&mut self, other: &SuggestionsBuilder) -> &mut SuggestionsBuilder { + self.result.extend(other.result.iter().cloned()); + self + } + + pub fn create_offset(&self, start: usize) -> SuggestionsBuilder { + SuggestionsBuilder::new_with_lowercase( + self.input.clone(), + self.input_lowercase.clone(), + start, + ) + } + + pub fn restart(&self) -> SuggestionsBuilder { + self.create_offset(self.start) + } +} diff --git a/azalea-brigadier/src/tree/argument_command_node.rs b/azalea-brigadier/src/tree/argument_command_node.rs index 4d38b41f..647b6c35 100644 --- a/azalea-brigadier/src/tree/argument_command_node.rs +++ b/azalea-brigadier/src/tree/argument_command_node.rs @@ -1,13 +1,14 @@ use std::fmt::{Display, Formatter}; use crate::{ - arguments::argument_type::ArgumentType, + arguments::argument_type::{ArgumentType, Types}, builder::required_argument_builder::RequiredArgumentBuilder, context::{ command_context::CommandContext, command_context_builder::CommandContextBuilder, parsed_argument::ParsedArgument, }, exceptions::command_syntax_exception::CommandSyntaxException, + immutable_string_reader::ImmutableStringReader, string_reader::StringReader, suggestion::{ suggestion_provider::SuggestionProvider, suggestions::Suggestions, @@ -20,11 +21,15 @@ use super::command_node::{BaseCommandNode, CommandNode}; const USAGE_ARGUMENT_OPEN: &str = "<"; const USAGE_ARGUMENT_CLOSE: &str = ">"; -#[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct ArgumentCommandNode<'a, S, T> { +pub struct ArgumentCommandNode<'a, S, T> +where + // each argument command node has its own different type + T: ArgumentType<dyn Types>, +{ name: String, type_: &'a T, - custom_suggestions: &'a dyn SuggestionProvider<S, T>, + custom_suggestions: Option<&'a dyn SuggestionProvider<S, 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<'a, S, T>, } @@ -34,12 +39,12 @@ impl<S, T> ArgumentCommandNode<'_, S, T> { &self.type_ } - fn custom_suggestions(&self) -> &dyn SuggestionProvider<S, T> { - &self.custom_suggestions + fn custom_suggestions(&self) -> Option<&dyn SuggestionProvider<S, T>> { + self.custom_suggestions } } -impl<S, T> CommandNode<S, T> for ArgumentCommandNode<'_, S, T> { +impl<'a, S, T> CommandNode<S, T> for ArgumentCommandNode<'a, S, T> { fn name(&self) -> &str { &self.name } @@ -56,7 +61,7 @@ impl<S, T> CommandNode<S, T> for ArgumentCommandNode<'_, S, T> { // contextBuilder.withArgument(name, parsed); // contextBuilder.withNode(this, parsed.getRange()); - let start = reader.get_cursor(); + let start = reader.cursor(); let result = self.get_type().parse(reader)?; let parsed = ParsedArgument::new(start, reader.get_cursor(), result); @@ -112,7 +117,7 @@ impl<S, T> CommandNode<S, T> for ArgumentCommandNode<'_, S, T> { } } -impl Display for ArgumentCommandNode<'_, String, String> { +impl Display for ArgumentCommandNode<'_, (), (), ()> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "<argument {}: {}>", self.name, self.type_) } diff --git a/azalea-brigadier/src/tree/command_node.rs b/azalea-brigadier/src/tree/command_node.rs index bcba9c03..8e262f0b 100644 --- a/azalea-brigadier/src/tree/command_node.rs +++ b/azalea-brigadier/src/tree/command_node.rs @@ -31,7 +31,7 @@ pub trait CommandNode<S, T> { fn usage_text(&self) -> &str; fn parse( &self, - reader: StringReader, + reader: &mut StringReader, context_builder: CommandContextBuilder<S, T>, ) -> Result<(), CommandSyntaxException>; fn list_suggestions( diff --git a/azalea-brigadier/src/tree/root_command_node.rs b/azalea-brigadier/src/tree/root_command_node.rs index 25a5a4b2..36787340 100644 --- a/azalea-brigadier/src/tree/root_command_node.rs +++ b/azalea-brigadier/src/tree/root_command_node.rs @@ -11,7 +11,6 @@ use crate::{ use super::command_node::{BaseCommandNode, CommandNode}; -#[derive(Hash, PartialEq, Eq, Debug, Clone)] 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<'a, S, T>, |
