azalea_brigadier/suggestion/
mod.rs1mod suggestions;
2mod suggestions_builder;
3
4#[cfg(feature = "azalea-buf")]
5use std::io::Write;
6use std::{
7 fmt::{self, Display},
8 hash::Hash,
9};
10
11#[cfg(feature = "azalea-buf")]
12use azalea_buf::AzaleaWrite;
13#[cfg(feature = "azalea-buf")]
14use azalea_chat::FormattedText;
15pub use suggestions::Suggestions;
16pub use suggestions_builder::SuggestionsBuilder;
17
18use crate::context::StringRange;
19
20#[derive(Debug, Clone, Hash, Eq, PartialEq)]
25pub struct Suggestion {
26 pub range: StringRange,
27 value: SuggestionValue,
28 pub tooltip: Option<String>,
29}
30
31#[derive(Debug, Clone, Hash, Eq, PartialEq)]
32pub enum SuggestionValue {
33 Integer(i32),
34 Text(String),
35}
36
37impl Suggestion {
38 pub fn new(range: StringRange, text: &str) -> Suggestion {
39 Suggestion {
40 range,
41 value: SuggestionValue::Text(text.to_string()),
42 tooltip: None,
43 }
44 }
45
46 pub fn new_with_tooltip(range: StringRange, text: &str, tooltip: String) -> Self {
47 Self {
48 range,
49 value: SuggestionValue::Text(text.to_string()),
50 tooltip: Some(tooltip),
51 }
52 }
53
54 pub fn apply(&self, input: &str) -> String {
55 let text = self.value.to_string();
56 if self.range.start() == 0 && self.range.end() == input.len() {
57 return text;
58 }
59 let mut result = String::with_capacity(text.len());
60 if self.range.start() > 0 {
61 result.push_str(&input[0..self.range.start()]);
62 }
63 result.push_str(&text);
64 if self.range.end() < input.len() {
65 result.push_str(&input[self.range.end()..]);
66 }
67
68 result
69 }
70
71 pub fn expand(&self, command: &str, range: StringRange) -> Suggestion {
72 if range == self.range {
73 return self.clone();
74 }
75 let mut result = String::new();
76 if range.start() < self.range.start() {
77 result.push_str(&command[range.start()..self.range.start()]);
78 }
79 result.push_str(&self.value.to_string());
80 if range.end() > self.range.end() {
81 result.push_str(&command[self.range.end()..range.end()]);
82 }
83 Suggestion {
84 range,
85 value: SuggestionValue::Text(result),
86 tooltip: self.tooltip.clone(),
87 }
88 }
89
90 pub fn text(&self) -> String {
91 self.value.to_string()
92 }
93}
94
95impl SuggestionValue {
96 pub fn cmp_ignore_case(&self, other: &Self) -> std::cmp::Ordering {
97 match (self, other) {
98 (SuggestionValue::Text(a), SuggestionValue::Text(b)) => {
99 a.to_lowercase().cmp(&b.to_lowercase())
100 }
101 (SuggestionValue::Integer(a), SuggestionValue::Integer(b)) => a.cmp(b),
102 _ => {
103 let a = self.to_string();
104 let b = other.to_string();
105 a.cmp(&b)
106 }
107 }
108 }
109}
110
111impl Display for SuggestionValue {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 match self {
114 SuggestionValue::Text(text) => write!(f, "{text}"),
115 SuggestionValue::Integer(value) => write!(f, "{value}"),
116 }
117 }
118}
119
120impl Ord for SuggestionValue {
121 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
122 match (self, other) {
123 (SuggestionValue::Text(a), SuggestionValue::Text(b)) => a.cmp(b),
124 (SuggestionValue::Integer(a), SuggestionValue::Integer(b)) => a.cmp(b),
125 _ => {
126 let a = self.to_string();
127 let b = other.to_string();
128 a.cmp(&b)
129 }
130 }
131 }
132}
133impl PartialOrd for SuggestionValue {
134 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
135 Some(self.cmp(other))
136 }
137}
138
139#[cfg(feature = "azalea-buf")]
140impl AzaleaWrite for Suggestion {
141 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
142 self.value.to_string().azalea_write(buf)?;
143 self.tooltip
144 .clone()
145 .map(FormattedText::from)
146 .azalea_write(buf)?;
147 Ok(())
148 }
149}