From cc4fe62fc82842e0bde628437a45d55c6a82f1f3 Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 11 Jan 2022 00:01:47 -0600 Subject: adfsfasdfaSDQAWERTERYTUYghyubnjnrdfxcv etgvbhy0ujn- --- azalea-brigadier/src/arguments/argument_type.rs | 6 +- .../src/arguments/bool_argument_type.rs | 6 +- azalea-brigadier/src/context/command_context.rs | 11 +- .../src/context/command_context_builder.rs | 2 +- azalea-brigadier/src/context/parsed_argument.rs | 2 +- .../src/context/parsed_command_node.rs | 9 +- azalea-brigadier/src/context/string_range.rs | 2 +- azalea-brigadier/src/message.rs | 1 + azalea-brigadier/src/suggestion/suggestion.rs | 90 ++++++++++++++++ azalea-brigadier/src/suggestion/suggestions.rs | 58 +++++++++++ .../src/suggestion/suggestions_builder.rs | 115 ++++++++++++++++++++- azalea-brigadier/src/tree/argument_command_node.rs | 23 +++-- azalea-brigadier/src/tree/command_node.rs | 2 +- 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 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 { 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, arguments: HashMap>, root_node: &'a dyn CommandNode, - nodes: Vec>, + nodes: Vec>, range: StringRange, - child: Option>, + child: Option<&'a CommandContext<'a, S, T>>, modifier: Option<&'a dyn RedirectModifier>, forks: bool, } -impl CommandContext<'_, S, T> { +impl 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>, root_node: &'a dyn CommandNode, - nodes: Vec>, + nodes: Vec>, dispatcher: CommandDispatcher<'a, S, T>, source: S, command: Box>, 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 { 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, +pub struct ParsedCommandNode { + node: Box>, range: StringRange, } -impl ParsedCommandNode<'_, S, T> { - fn new(node: &dyn CommandNode, range: StringRange) -> Self { +impl ParsedCommandNode { + fn new(node: dyn CommandNode, 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); 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, +} + +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 { + 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, +} + +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, +{ name: String, type_: &'a T, - custom_suggestions: &'a dyn SuggestionProvider, + custom_suggestions: Option<&'a dyn SuggestionProvider>, + // custom_suggestions: &'a dyn SuggestionProvider, // 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 ArgumentCommandNode<'_, S, T> { &self.type_ } - fn custom_suggestions(&self) -> &dyn SuggestionProvider { - &self.custom_suggestions + fn custom_suggestions(&self) -> Option<&dyn SuggestionProvider> { + self.custom_suggestions } } -impl CommandNode for ArgumentCommandNode<'_, S, T> { +impl<'a, S, T> CommandNode for ArgumentCommandNode<'a, S, T> { fn name(&self) -> &str { &self.name } @@ -56,7 +61,7 @@ impl CommandNode 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 CommandNode 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, "", 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 { fn usage_text(&self) -> &str; fn parse( &self, - reader: StringReader, + reader: &mut StringReader, context_builder: CommandContextBuilder, ) -> 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>, -- cgit v1.2.3