azalea_brigadier/suggestion/
suggestions.rs1#[cfg(feature = "azalea-buf")]
2use std::io::{Cursor, Write};
3use std::{collections::HashSet, hash::Hash};
4
5#[cfg(feature = "azalea-buf")]
6use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
7#[cfg(feature = "azalea-buf")]
8use azalea_chat::FormattedText;
9
10use super::Suggestion;
11use crate::context::StringRange;
12#[cfg(feature = "azalea-buf")]
13use crate::suggestion::SuggestionValue;
14
15#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
16pub struct Suggestions {
17 range: StringRange,
18 suggestions: Vec<Suggestion>,
19}
20
21impl Suggestions {
22 pub fn new(range: StringRange, suggestions: Vec<Suggestion>) -> Self {
23 Self { range, suggestions }
24 }
25
26 pub fn merge(command: &str, input: &[Suggestions]) -> Self {
27 if input.is_empty() {
28 return Suggestions::default();
29 } else if input.len() == 1 {
30 return input[0].clone();
31 };
32
33 let mut texts = HashSet::new();
34 for suggestions in input {
35 texts.extend(suggestions.suggestions.clone());
36 }
37
38 Suggestions::create(command, &texts)
39 }
40
41 pub fn create(command: &str, suggestions: &HashSet<Suggestion>) -> Self {
42 if suggestions.is_empty() {
43 return Suggestions::default();
44 };
45 let mut start = usize::MAX;
46 let mut end = usize::MIN;
47 for suggestion in suggestions {
48 start = suggestion.range.start().min(start);
49 end = suggestion.range.end().max(end);
50 }
51 let range = StringRange::new(start, end);
52 let mut texts = HashSet::new();
53 for suggestion in suggestions {
54 texts.insert(suggestion.expand(command, range));
55 }
56 let mut sorted = texts.into_iter().collect::<Vec<_>>();
57
58 sorted.sort_by(|a, b| a.value.cmp_ignore_case(&b.value));
59
60 Suggestions {
61 range,
62 suggestions: sorted,
63 }
64 }
65
66 pub fn is_empty(&self) -> bool {
67 self.suggestions.is_empty()
68 }
69
70 pub fn list(&self) -> &[Suggestion] {
71 &self.suggestions
72 }
73
74 pub fn range(&self) -> StringRange {
75 self.range
76 }
77}
78
79#[cfg(feature = "azalea-buf")]
80impl AzaleaRead for Suggestions {
81 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
82 #[derive(AzBuf)]
83 struct StandaloneSuggestion {
84 pub text: String,
85 pub tooltip: Option<FormattedText>,
86 }
87
88 let start = u32::azalea_read_var(buf)? as usize;
89 let length = u32::azalea_read_var(buf)? as usize;
90 let range = StringRange::between(start, start + length);
91
92 let mut suggestions = Vec::<StandaloneSuggestion>::azalea_read(buf)?
95 .into_iter()
96 .map(|s| Suggestion {
97 value: SuggestionValue::Text(s.text),
98 tooltip: s.tooltip.map(|t| t.to_string()),
99 range,
100 })
101 .collect::<Vec<_>>();
102 suggestions.sort_by(|a, b| a.value.cmp(&b.value));
103
104 Ok(Suggestions { range, suggestions })
105 }
106}
107
108#[cfg(feature = "azalea-buf")]
109impl AzaleaWrite for Suggestions {
110 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
111 (self.range.start() as u32).azalea_write_var(buf)?;
112 (self.range.length() as u32).azalea_write_var(buf)?;
113 self.suggestions.azalea_write(buf)?;
114 Ok(())
115 }
116}