start adding brigadier suggestions

This commit is contained in:
mat 2023-10-01 19:12:27 -05:00
parent 8b65d7c95e
commit 2606de9f4c
4 changed files with 186 additions and 1 deletions

View file

@ -1,4 +1,5 @@
mod suggestions;
mod suggestions_builder;
use crate::context::StringRange;
#[cfg(feature = "azalea-buf")]
@ -7,7 +8,8 @@ use azalea_buf::McBufWritable;
use azalea_chat::FormattedText;
#[cfg(feature = "azalea-buf")]
use std::io::Write;
pub use suggestions::*;
pub use suggestions::Suggestions;
pub use suggestions_builder::SuggestionsBuilder;
/// A suggestion given to the user for what they might want to type next.
///

View file

@ -0,0 +1,92 @@
use std::collections::HashSet;
use crate::context::StringRange;
use super::{Suggestion, Suggestions};
pub struct SuggestionsBuilder {
input: String,
input_lowercase: String,
start: usize,
remaining: String,
remaining_lowercase: String,
result: HashSet<Suggestion>,
}
impl SuggestionsBuilder {
pub fn new(input: &str, start: usize) -> Self {
Self::new_with_lowercase(input, input.to_lowercase().as_str(), start)
}
pub fn new_with_lowercase(input: &str, input_lowercase: &str, start: usize) -> Self {
Self {
start,
input: input.to_string(),
input_lowercase: input_lowercase.to_string(),
remaining: input[start..].to_string(),
remaining_lowercase: input_lowercase[start..].to_string(),
result: HashSet::new(),
}
}
pub fn input(&self) -> &str {
&self.input
}
pub fn start(&self) -> usize {
self.start
}
pub fn remianing(&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) -> Self {
if text == self.remaining {
return self;
}
self.result.insert(Suggestion {
range: StringRange::between(self.start, self.input.len()),
text: text.to_string(),
tooltip: None,
});
self
}
pub fn suggest_with_tooltip(mut self, text: &str, tooltip: String) -> Self {
if text == self.remaining {
return self;
}
self.result.insert(Suggestion {
range: StringRange::between(self.start, self.input.len()),
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
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, other: SuggestionsBuilder) -> Self {
self.result.extend(other.result);
self
}
pub fn create_offset(&self, start: usize) -> Self {
SuggestionsBuilder::new_with_lowercase(&self.input, &self.input_lowercase, start)
}
pub fn restart(self) -> Self {
self.create_offset(self.start)
}
}

View file

@ -0,0 +1,71 @@
#[test]
fn apply_insertation_start() {
let suggestion = Suggestion::new(StringRange::at(0), "And so I said: ");
assert_eq!(suggestion.apply("Hello world!"), "And so I said: Hello world!");
}
#[test]
fn apply_insertation_middle() {
let suggestion = Suggestion::new(StringRange::at(6), "small ");
assert_eq!(suggestion.apply("Hello world!"), "Hello small world!");
}
#[test]
fn apply_insertation_end() {
let suggestion = Suggestion::new(StringRange::at(5), " world!");
assert_eq!(suggestion.apply("Hello"), "Hello world!");
}
#[test]
fn apply_replacement_start() {
let suggestion = Suggestion::new(StringRange::between(0, 5), "Goodbye");
assert_eq!(suggestion.apply("Hello world!"), "Goodbye world!");
}
#[test]
fn apply_replacement_middle() {
let suggestion = Suggestion::new(StringRange::between(6, 11), "Alex");
assert_eq!(suggestion.apply("Hello world!"), "Hello Alex!");
}
#[test]
fn apply_replacement_end() {
let suggestion = Suggestion::new(StringRange::between(6, 12), "Creeper!");
assert_eq!(suggestion.apply("Hello world!"), "Hello Creeper!");
}
#[test]
fn apply_replacement_everything() {
let suggestion = Suggestion::new(StringRange::between(0, 12), "Oh dear.");
assert_eq!(suggestion.apply("Hello world!"), "Oh dear.");
}
#[test]
fn expand_unchanged() {
let suggestion = Suggestion::new(StringRange::at(1), "oo");
assert_eq!(suggestion.expand("f", StringRange::at(1)), suggestion);
}
#[test]
fn expand_left() {
let suggestion = Suggestion::new(StringRange::at(1), "oo");
assert_eq!(suggestion.expand("f", StringRange::between(0, 1)), Suggestion::new(StringRange::between(0, 1), "foo"));
}
#[test]
fn expand_right() {
let suggestion = Suggestion::new(StringRange::at(0), "minecraft:");
assert_eq!(suggestion.expand("fish", StringRange::between(0, 4)), Suggestion::new(StringRange::between(0, 4), "minecraft:fish"));
}
#[test]
fn expand_both() {
let suggestion = Suggestion::new(StringRange::at(11), "minecraft:");
assert_eq!(suggestion.expand("give Steve fish_block", StringRange::between(5, 21)), Suggestion::new(StringRange::between(5, 21), "Steve minecraft:fish_block"));
}
#[test]
fn expand_replacement() {
let suggestion = Suggestion::new(StringRange::between(6, 11), "strangers");
assert_eq!(suggestion.expand("Hello world!", StringRange::between(0, 12)), Suggestion::new(StringRange::between(0, 12), "Hello strangers!"));
}

View file

@ -0,0 +1,20 @@
#[test]
fn merge_empty() {
let merged = Suggestions::merge("foo b", vec![]);
assert!(merged.is_empty());
}
#[test]
fn merge_single() {
let suggestions = Suggestions::new(StringRange::at(5), vec![Suggestion::new(StringRange::at(5), "ar")]);
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"), Suggestion::new(StringRange::at(5), "az"), Suggestion::new(StringRange::at(5), "Az")]);
let b = Suggestions::new(StringRange::between(4, 5), vec![Suggestion::new(StringRange::between(4, 5), "foo"), Suggestion::new(StringRange::between(4, 5), "qux"), Suggestion::new(StringRange::between(4, 5), "apple"), Suggestion::new(StringRange::between(4, 5), "Bar")]);
let merged = Suggestions::merge("foo b", vec![a, b]);
assert_eq!(merged.get_list(), vec![Suggestion::new(StringRange::between(4, 5), "apple"), Suggestion::new(StringRange::between(4, 5), "ar"), Suggestion::new(StringRange::between(4, 5), "Az"), Suggestion::new(StringRange::between(4, 5), "bar"), Suggestion::new(StringRange::between(4, 5), "Bar"), Suggestion::new(StringRange::between(4, 5), "baz"), Suggestion::new(StringRange::between(4, 5), "bAz"), Suggestion::new(StringRange::between(4, 5), "foo"), Suggestion::new(StringRange::between(4, 5), "qux")]);
}