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