azalea_brigadier/tree/
mod.rs

1use std::{
2    collections::{BTreeMap, HashMap},
3    fmt::{self, Debug},
4    hash::{Hash, Hasher},
5    ptr,
6    sync::Arc,
7};
8
9use parking_lot::RwLock;
10
11use crate::{
12    builder::{
13        argument_builder::ArgumentBuilderType, literal_argument_builder::Literal,
14        required_argument_builder::Argument,
15    },
16    context::{CommandContext, CommandContextBuilder, ParsedArgument, StringRange},
17    errors::{BuiltInError, CommandSyntaxError},
18    modifier::RedirectModifier,
19    string_reader::StringReader,
20    suggestion::{Suggestions, SuggestionsBuilder},
21};
22
23pub type Command<S> =
24    Option<Arc<dyn Fn(&CommandContext<S>) -> Result<i32, CommandSyntaxError> + Send + Sync>>;
25
26/// An ArgumentBuilder that has been built.
27#[non_exhaustive]
28pub struct CommandNode<S> {
29    pub value: ArgumentBuilderType<S>,
30
31    // this is a BTreeMap because children need to be ordered when getting command suggestions
32    pub children: BTreeMap<String, Arc<RwLock<CommandNode<S>>>>,
33    pub literals: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
34    pub arguments: HashMap<String, Arc<RwLock<CommandNode<S>>>>,
35
36    pub command: Command<S>,
37    pub requirement: Arc<dyn Fn(&S) -> bool + Send + Sync>,
38    pub redirect: Option<Arc<RwLock<CommandNode<S>>>>,
39    pub forks: bool,
40    pub modifier: Option<Arc<RedirectModifier<S>>>,
41}
42
43impl<S> Clone for CommandNode<S> {
44    fn clone(&self) -> Self {
45        Self {
46            value: self.value.clone(),
47            children: self.children.clone(),
48            literals: self.literals.clone(),
49            arguments: self.arguments.clone(),
50            command: self.command.clone(),
51            requirement: self.requirement.clone(),
52            redirect: self.redirect.clone(),
53            forks: self.forks,
54            modifier: self.modifier.clone(),
55        }
56    }
57}
58
59impl<S> CommandNode<S> {
60    /// Gets the literal, or panics. You should use match if you're not certain
61    /// about the type.
62    pub fn literal(&self) -> &Literal {
63        match self.value {
64            ArgumentBuilderType::Literal(ref literal) => literal,
65            _ => panic!("CommandNode::literal() called on non-literal node"),
66        }
67    }
68    /// Gets the argument, or panics. You should use match if you're not certain
69    /// about the type.
70    pub fn argument(&self) -> &Argument<S> {
71        match self.value {
72            ArgumentBuilderType::Argument(ref argument) => argument,
73            _ => panic!("CommandNode::argument() called on non-argument node"),
74        }
75    }
76
77    pub fn get_relevant_nodes(&self, input: &mut StringReader) -> Vec<Arc<RwLock<CommandNode<S>>>> {
78        let literals = &self.literals;
79
80        if literals.is_empty() {
81            self.arguments.values().cloned().collect()
82        } else {
83            let cursor = input.cursor();
84            while input.can_read() && input.peek() != ' ' {
85                input.skip();
86            }
87            let text: String = input
88                .string()
89                .chars()
90                .skip(cursor)
91                .take(input.cursor() - cursor)
92                .collect();
93            input.cursor = cursor;
94            let literal = literals.get(&text);
95            if let Some(literal) = literal {
96                vec![literal.clone()]
97            } else {
98                self.arguments.values().cloned().collect()
99            }
100        }
101    }
102
103    pub fn can_use(&self, source: &S) -> bool {
104        (self.requirement)(source)
105    }
106
107    pub fn add_child(&mut self, node: &Arc<RwLock<CommandNode<S>>>) {
108        let child = self.children.get(node.read().name());
109        if let Some(child) = child {
110            // We've found something to merge onto
111            if let Some(command) = &node.read().command {
112                child.write().command = Some(command.clone());
113            }
114            for grandchild in node.read().children.values() {
115                child.write().add_child(grandchild);
116            }
117        } else {
118            self.children
119                .insert(node.read().name().to_string(), node.clone());
120            match &node.read().value {
121                ArgumentBuilderType::Literal(literal) => {
122                    self.literals.insert(literal.value.clone(), node.clone());
123                }
124                ArgumentBuilderType::Argument(argument) => {
125                    self.arguments.insert(argument.name.clone(), node.clone());
126                }
127            }
128        }
129    }
130
131    pub fn name(&self) -> &str {
132        match &self.value {
133            ArgumentBuilderType::Argument(argument) => &argument.name,
134            ArgumentBuilderType::Literal(literal) => &literal.value,
135        }
136    }
137
138    pub fn usage_text(&self) -> String {
139        match &self.value {
140            ArgumentBuilderType::Argument(argument) => format!("<{}>", argument.name),
141            ArgumentBuilderType::Literal(literal) => literal.value.to_owned(),
142        }
143    }
144
145    pub fn child(&self, name: &str) -> Option<Arc<RwLock<CommandNode<S>>>> {
146        self.children.get(name).cloned()
147    }
148
149    pub fn parse_with_context(
150        &self,
151        reader: &mut StringReader,
152        context_builder: &mut CommandContextBuilder<S>,
153    ) -> Result<(), CommandSyntaxError> {
154        match self.value {
155            ArgumentBuilderType::Argument(ref argument) => {
156                let start = reader.cursor();
157                let result = argument.parse(reader)?;
158                let parsed = ParsedArgument {
159                    range: StringRange::between(start, reader.cursor()),
160                    result,
161                };
162
163                context_builder.with_argument(&argument.name, parsed.clone());
164                context_builder.with_node(Arc::new(RwLock::new(self.clone())), parsed.range);
165
166                Ok(())
167            }
168            ArgumentBuilderType::Literal(ref literal) => {
169                let start = reader.cursor();
170                let end = self.parse(reader);
171
172                if let Some(end) = end {
173                    context_builder.with_node(
174                        Arc::new(RwLock::new(self.clone())),
175                        StringRange::between(start, end),
176                    );
177                    return Ok(());
178                }
179
180                Err(BuiltInError::LiteralIncorrect {
181                    expected: literal.value.clone(),
182                }
183                .create_with_context(reader))
184            }
185        }
186    }
187
188    fn parse(&self, reader: &mut StringReader) -> Option<usize> {
189        match self.value {
190            ArgumentBuilderType::Argument(_) => {
191                panic!("Can't parse argument.")
192            }
193            ArgumentBuilderType::Literal(ref literal) => {
194                let start = reader.cursor();
195                if reader.can_read_length(literal.value.len()) {
196                    let end = start + literal.value.len();
197                    if reader
198                        .string()
199                        .get(start..end)
200                        .expect("Couldn't slice reader correctly?")
201                        == literal.value
202                    {
203                        reader.cursor = end;
204                        if !reader.can_read() || reader.peek() == ' ' {
205                            return Some(end);
206                        } else {
207                            reader.cursor = start;
208                        }
209                    }
210                }
211            }
212        }
213        None
214    }
215
216    pub fn list_suggestions(
217        &self,
218        context: CommandContext<S>,
219        builder: SuggestionsBuilder,
220    ) -> Suggestions {
221        match &self.value {
222            ArgumentBuilderType::Literal(literal) => {
223                if literal
224                    .value
225                    .to_lowercase()
226                    .starts_with(builder.remaining_lowercase())
227                {
228                    builder.suggest(&literal.value).build()
229                } else {
230                    Suggestions::default()
231                }
232            }
233            ArgumentBuilderType::Argument(argument) => argument.list_suggestions(context, builder),
234        }
235    }
236}
237
238impl<S> Debug for CommandNode<S> {
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        f.debug_struct("CommandNode")
241            // .field("value", &self.value)
242            .field("children", &self.children)
243            .field("command", &self.command.is_some())
244            // .field("requirement", &self.requirement)
245            .field("redirect", &self.redirect)
246            .field("forks", &self.forks)
247            // .field("modifier", &self.modifier)
248            .finish()
249    }
250}
251
252impl<S> Default for CommandNode<S> {
253    fn default() -> Self {
254        Self {
255            value: ArgumentBuilderType::Literal(Literal::default()),
256
257            children: BTreeMap::new(),
258            literals: HashMap::new(),
259            arguments: HashMap::new(),
260
261            command: None,
262            requirement: Arc::new(|_| true),
263            redirect: None,
264            forks: false,
265            modifier: None,
266        }
267    }
268}
269
270impl<S> Hash for CommandNode<S> {
271    fn hash<H: Hasher>(&self, state: &mut H) {
272        // hash the children
273        for (k, v) in &self.children {
274            k.hash(state);
275            v.read().hash(state);
276        }
277        // i hope this works because if doesn't then that'll be a problem
278        ptr::hash(&self.command, state);
279    }
280}
281
282impl<S> PartialEq for CommandNode<S> {
283    fn eq(&self, other: &Self) -> bool {
284        if self.children.len() != other.children.len() {
285            return false;
286        }
287        for (k, v) in &self.children {
288            let other_child = other.children.get(k).unwrap();
289            if !Arc::ptr_eq(v, other_child) {
290                return false;
291            }
292        }
293
294        match &self.command {
295            Some(selfexecutes) => {
296                // idk how to do this better since we can't compare `dyn Fn`s
297                match &other.command {
298                    Some(otherexecutes) =>
299                    {
300                        #[allow(ambiguous_wide_pointer_comparisons)]
301                        if !Arc::ptr_eq(selfexecutes, otherexecutes) {
302                            return false;
303                        }
304                    }
305                    _ => {
306                        return false;
307                    }
308                }
309            }
310            _ => {
311                if other.command.is_some() {
312                    return false;
313                }
314            }
315        }
316        true
317    }
318}
319impl<S> Eq for CommandNode<S> {}