aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/src/suggestion
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2023-10-12 20:14:29 -0500
committermat <git@matdoes.dev>2023-10-12 20:14:29 -0500
commit38db231ea8fa0fb223e16637db0b6ec65b2b81ef (patch)
treef8f61b04ad0b498b85bffb133c51af1670a33ddf /azalea-brigadier/src/suggestion
parentd5f424b8c2fba9b3283aef36fe9e1e051636614c (diff)
downloadazalea-drasl-38db231ea8fa0fb223e16637db0b6ec65b2b81ef.tar.xz
brigadier usages
Diffstat (limited to 'azalea-brigadier/src/suggestion')
-rwxr-xr-xazalea-brigadier/src/suggestion/mod.rs102
-rwxr-xr-xazalea-brigadier/src/suggestion/suggestions.rs39
-rwxr-xr-xazalea-brigadier/src/suggestion/suggestions_builder.rs50
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)
}
}