diff options
| author | mat <git@matdoes.dev> | 2023-10-12 20:14:29 -0500 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2023-10-12 20:14:29 -0500 |
| commit | 38db231ea8fa0fb223e16637db0b6ec65b2b81ef (patch) | |
| tree | f8f61b04ad0b498b85bffb133c51af1670a33ddf /azalea-brigadier/src/suggestion | |
| parent | d5f424b8c2fba9b3283aef36fe9e1e051636614c (diff) | |
| download | azalea-drasl-38db231ea8fa0fb223e16637db0b6ec65b2b81ef.tar.xz | |
brigadier usages
Diffstat (limited to 'azalea-brigadier/src/suggestion')
| -rwxr-xr-x | azalea-brigadier/src/suggestion/mod.rs | 102 | ||||
| -rwxr-xr-x | azalea-brigadier/src/suggestion/suggestions.rs | 39 | ||||
| -rwxr-xr-x | azalea-brigadier/src/suggestion/suggestions_builder.rs | 50 |
3 files changed, 158 insertions, 33 deletions
diff --git a/azalea-brigadier/src/suggestion/mod.rs b/azalea-brigadier/src/suggestion/mod.rs index c404adc7..bc0e7608 100755 --- a/azalea-brigadier/src/suggestion/mod.rs +++ b/azalea-brigadier/src/suggestion/mod.rs @@ -8,6 +8,10 @@ use azalea_buf::McBufWritable; use azalea_chat::FormattedText; #[cfg(feature = "azalea-buf")] use std::io::Write; +use std::{ + fmt::{self, Display}, + hash::Hash, +}; pub use suggestions::Suggestions; pub use suggestions_builder::SuggestionsBuilder; @@ -16,22 +20,50 @@ pub use suggestions_builder::SuggestionsBuilder; /// The `M` generic is the type of the tooltip, so for example a `String` or /// just `()` if you don't care about it. #[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct Suggestion<M = String> { - pub text: String, +pub struct Suggestion<M = ()> +where + M: Clone, +{ pub range: StringRange, + value: SuggestionValue, pub tooltip: Option<M>, } +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub enum SuggestionValue { + Integer(i32), + Text(String), +} + +impl Suggestion<()> { + pub fn new(range: StringRange, text: &str) -> Suggestion<()> { + Suggestion { + range, + value: SuggestionValue::Text(text.to_string()), + tooltip: None, + } + } +} + impl<M: Clone> Suggestion<M> { + pub fn new_with_tooltip(range: StringRange, text: &str, tooltip: M) -> Self { + Self { + range, + value: SuggestionValue::Text(text.to_string()), + tooltip: Some(tooltip), + } + } + pub fn apply(&self, input: &str) -> String { + let text = self.value.to_string(); if self.range.start() == 0 && self.range.end() == input.len() { - return input.to_string(); + return text; } - let mut result = String::with_capacity(self.text.len()); + let mut result = String::with_capacity(text.len()); if self.range.start() > 0 { result.push_str(&input[0..self.range.start()]); } - result.push_str(&self.text); + result.push_str(&text); if self.range.end() < input.len() { result.push_str(&input[self.range.end()..]); } @@ -39,30 +71,78 @@ impl<M: Clone> Suggestion<M> { result } - pub fn expand(&self, command: &str, range: &StringRange) -> Suggestion<M> { - if range == &self.range { + pub fn expand(&self, command: &str, range: StringRange) -> Suggestion<M> { + 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); + result.push_str(&self.value.to_string()); if range.end() > self.range.end() { result.push_str(&command[self.range.end()..range.end()]); } Suggestion { - range: range.clone(), - text: result, + range, + value: SuggestionValue::Text(result), tooltip: self.tooltip.clone(), } } + + pub fn text(&self) -> String { + self.value.to_string() + } +} + +impl SuggestionValue { + pub fn cmp_ignore_case(&self, other: &Self) -> std::cmp::Ordering { + match (self, other) { + (SuggestionValue::Text(a), SuggestionValue::Text(b)) => { + a.to_lowercase().cmp(&b.to_lowercase()) + } + (SuggestionValue::Integer(a), SuggestionValue::Integer(b)) => a.cmp(b), + _ => { + let a = self.to_string(); + let b = other.to_string(); + a.cmp(&b) + } + } + } +} + +impl Display for SuggestionValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SuggestionValue::Text(text) => write!(f, "{text}"), + SuggestionValue::Integer(value) => write!(f, "{value}"), + } + } +} + +impl Ord for SuggestionValue { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match (self, other) { + (SuggestionValue::Text(a), SuggestionValue::Text(b)) => a.cmp(b), + (SuggestionValue::Integer(a), SuggestionValue::Integer(b)) => a.cmp(b), + _ => { + let a = self.to_string(); + let b = other.to_string(); + a.cmp(&b) + } + } + } +} +impl PartialOrd for SuggestionValue { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) + } } #[cfg(feature = "azalea-buf")] impl McBufWritable for Suggestion<FormattedText> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { - self.text.write_into(buf)?; + self.value.to_string().write_into(buf)?; self.tooltip.write_into(buf)?; Ok(()) } diff --git a/azalea-brigadier/src/suggestion/suggestions.rs b/azalea-brigadier/src/suggestion/suggestions.rs index 2a8b5e9e..69877786 100755 --- a/azalea-brigadier/src/suggestion/suggestions.rs +++ b/azalea-brigadier/src/suggestion/suggestions.rs @@ -1,6 +1,8 @@ use super::Suggestion; use crate::context::StringRange; #[cfg(feature = "azalea-buf")] +use crate::suggestion::SuggestionValue; +#[cfg(feature = "azalea-buf")] use azalea_buf::{ BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, }; @@ -11,12 +13,19 @@ use std::io::{Cursor, Write}; use std::{collections::HashSet, hash::Hash}; #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Suggestions<M = String> { - pub range: StringRange, - pub suggestions: Vec<Suggestion<M>>, +pub struct Suggestions<M> +where + M: Clone + PartialEq + Hash, +{ + range: StringRange, + suggestions: Vec<Suggestion<M>>, } impl<M: Clone + Eq + Hash> Suggestions<M> { + pub fn new(range: StringRange, suggestions: Vec<Suggestion<M>>) -> Self { + Self { range, suggestions } + } + pub fn merge(command: &str, input: &[Suggestions<M>]) -> Self { if input.is_empty() { return Suggestions::default(); @@ -45,20 +54,34 @@ impl<M: Clone + Eq + Hash> Suggestions<M> { let range = StringRange::new(start, end); let mut texts = HashSet::new(); for suggestion in suggestions { - texts.insert(suggestion.expand(command, &range)); + texts.insert(suggestion.expand(command, range)); } let mut sorted = texts.into_iter().collect::<Vec<_>>(); - sorted.sort_by(|a, b| a.text.cmp(&b.text)); + + sorted.sort_by(|a, b| a.value.cmp_ignore_case(&b.value)); + Suggestions { range, suggestions: sorted, } } + + pub fn is_empty(&self) -> bool { + self.suggestions.is_empty() + } + + pub fn list(&self) -> &[Suggestion<M>] { + &self.suggestions + } + + pub fn range(&self) -> StringRange { + self.range + } } // this can't be derived because that'd require the generic to have `Default` // too even if it's not actually necessary -impl<M> Default for Suggestions<M> { +impl<M: Clone + Hash + Eq> Default for Suggestions<M> { fn default() -> Self { Self { range: StringRange::default(), @@ -85,12 +108,12 @@ impl McBufReadable for Suggestions<FormattedText> { let mut suggestions = Vec::<StandaloneSuggestion>::read_from(buf)? .into_iter() .map(|s| Suggestion { - text: s.text, + value: SuggestionValue::Text(s.text), tooltip: s.tooltip, range: range.clone(), }) .collect::<Vec<_>>(); - suggestions.sort_by(|a, b| a.text.cmp(&b.text)); + suggestions.sort_by(|a, b| a.value.cmp(&b.value)); Ok(Suggestions { range, suggestions }) } diff --git a/azalea-brigadier/src/suggestion/suggestions_builder.rs b/azalea-brigadier/src/suggestion/suggestions_builder.rs index 66f17fb1..469a7b98 100755 --- a/azalea-brigadier/src/suggestion/suggestions_builder.rs +++ b/azalea-brigadier/src/suggestion/suggestions_builder.rs @@ -1,19 +1,24 @@ use std::collections::HashSet; +use std::hash::Hash; use crate::context::StringRange; -use super::{Suggestion, Suggestions}; +use super::{Suggestion, SuggestionValue, Suggestions}; -pub struct SuggestionsBuilder { +#[derive(PartialEq, Debug)] +pub struct SuggestionsBuilder<M = ()> +where + M: Clone + Eq + Hash, +{ input: String, input_lowercase: String, start: usize, remaining: String, remaining_lowercase: String, - result: HashSet<Suggestion>, + result: HashSet<Suggestion<M>>, } -impl SuggestionsBuilder { +impl SuggestionsBuilder<()> { pub fn new(input: &str, start: usize) -> Self { Self::new_with_lowercase(input, input.to_lowercase().as_str(), start) } @@ -28,7 +33,9 @@ impl SuggestionsBuilder { result: HashSet::new(), } } +} +impl<M: Clone + Eq + Hash> SuggestionsBuilder<M> { pub fn input(&self) -> &str { &self.input } @@ -37,7 +44,7 @@ impl SuggestionsBuilder { self.start } - pub fn remianing(&self) -> &str { + pub fn remaining(&self) -> &str { &self.remaining } @@ -45,7 +52,7 @@ impl SuggestionsBuilder { &self.remaining_lowercase } - pub fn build(&self) -> Suggestions { + pub fn build(&self) -> Suggestions<M> { Suggestions::create(&self.input, &self.result) } @@ -55,38 +62,53 @@ impl SuggestionsBuilder { } self.result.insert(Suggestion { range: StringRange::between(self.start, self.input.len()), - text: text.to_string(), + value: SuggestionValue::Text(text.to_string()), tooltip: None, }); self } - pub fn suggest_with_tooltip(mut self, text: &str, tooltip: String) -> Self { + pub fn suggest_with_tooltip(mut self, text: &str, tooltip: M) -> Self { if text == self.remaining { return self; } self.result.insert(Suggestion { range: StringRange::between(self.start, self.input.len()), - text: text.to_string(), + value: SuggestionValue::Text(text.to_string()), tooltip: Some(tooltip), }); self } - // TODO: integer suggestions - // https://github.com/Mojang/brigadier/blob/master/src/main/java/com/mojang/brigadier/suggestion/SuggestionsBuilder.java#L74 + pub fn suggest_integer(mut self, value: i32) -> Self { + self.result.insert(Suggestion { + range: StringRange::between(self.start, self.input.len()), + value: SuggestionValue::Integer(value), + tooltip: None, + }); + self + } + + pub fn suggest_integer_with_tooltip(mut self, value: i32, tooltip: M) -> Self { + self.result.insert(Suggestion { + range: StringRange::between(self.start, self.input.len()), + value: SuggestionValue::Integer(value), + tooltip: Some(tooltip), + }); + self + } #[allow(clippy::should_implement_trait)] - pub fn add(mut self, other: SuggestionsBuilder) -> Self { + pub fn add(mut self, other: SuggestionsBuilder<M>) -> Self { self.result.extend(other.result); self } - pub fn create_offset(&self, start: usize) -> Self { + pub fn create_offset(&self, start: usize) -> SuggestionsBuilder<()> { SuggestionsBuilder::new_with_lowercase(&self.input, &self.input_lowercase, start) } - pub fn restart(self) -> Self { + pub fn restart(&self) -> SuggestionsBuilder<()> { self.create_offset(self.start) } } |
