azalea_brigadier/context/
command_context_builder.rs

1use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
2
3use parking_lot::RwLock;
4
5use super::{
6    ParsedArgument, command_context::CommandContext, parsed_command_node::ParsedCommandNode,
7    string_range::StringRange, suggestion_context::SuggestionContext,
8};
9use crate::{
10    command_dispatcher::CommandDispatcher,
11    modifier::RedirectModifier,
12    tree::{Command, CommandNode},
13};
14
15pub struct CommandContextBuilder<'a, S> {
16    pub arguments: HashMap<String, ParsedArgument>,
17    pub root: Arc<RwLock<CommandNode<S>>>,
18    pub nodes: Vec<ParsedCommandNode<S>>,
19    pub dispatcher: &'a CommandDispatcher<S>,
20    pub source: Arc<S>,
21    pub command: Command<S>,
22    pub child: Option<Rc<CommandContextBuilder<'a, S>>>,
23    pub range: StringRange,
24    pub modifier: Option<Arc<RedirectModifier<S>>>,
25    pub forks: bool,
26}
27
28impl<S> Clone for CommandContextBuilder<'_, S> {
29    fn clone(&self) -> Self {
30        Self {
31            arguments: self.arguments.clone(),
32            root: self.root.clone(),
33            nodes: self.nodes.clone(),
34            dispatcher: self.dispatcher,
35            source: self.source.clone(),
36            command: self.command.clone(),
37            child: self.child.clone(),
38            range: self.range,
39            modifier: self.modifier.clone(),
40            forks: self.forks,
41        }
42    }
43}
44
45impl<'a, S> CommandContextBuilder<'a, S> {
46    pub fn new(
47        dispatcher: &'a CommandDispatcher<S>,
48        source: Arc<S>,
49        root_node: Arc<RwLock<CommandNode<S>>>,
50        start: usize,
51    ) -> Self {
52        Self {
53            arguments: HashMap::new(),
54            root: root_node,
55            source,
56            range: StringRange::at(start),
57            command: None,
58            dispatcher,
59            nodes: vec![],
60            child: None,
61            modifier: None,
62            forks: false,
63        }
64    }
65
66    pub fn with_command(&mut self, command: &Command<S>) -> &Self {
67        self.command.clone_from(command);
68        self
69    }
70    pub fn with_child(&mut self, child: Rc<CommandContextBuilder<'a, S>>) -> &Self {
71        self.child = Some(child);
72        self
73    }
74    pub fn with_argument(&mut self, name: &str, argument: ParsedArgument) -> &Self {
75        self.arguments.insert(name.to_string(), argument);
76        self
77    }
78    pub fn with_node(&mut self, node: Arc<RwLock<CommandNode<S>>>, range: StringRange) -> &Self {
79        self.nodes.push(ParsedCommandNode {
80            node: node.clone(),
81            range,
82        });
83        self.range = StringRange::encompassing(&self.range, &range);
84        self.modifier.clone_from(&node.read().modifier);
85        self.forks = node.read().forks;
86        self
87    }
88
89    pub fn build(&self, input: &str) -> CommandContext<S> {
90        CommandContext {
91            arguments: self.arguments.clone(),
92            root_node: self.root.clone(),
93            nodes: self.nodes.clone(),
94            source: self.source.clone(),
95            command: self.command.clone(),
96            child: self.child.clone().map(|c| Rc::new(c.build(input))),
97            range: self.range,
98            forks: self.forks,
99            modifier: self.modifier.clone(),
100            input: input.to_string(),
101        }
102    }
103
104    pub fn find_suggestion_context(&self, cursor: usize) -> SuggestionContext<S> {
105        if self.range.start() > cursor {
106            panic!("Can't find node before cursor");
107        }
108
109        if self.range.end() < cursor {
110            match &self.child {
111                Some(child) => child.find_suggestion_context(cursor),
112                _ => match self.nodes.last() {
113                    Some(last) => SuggestionContext {
114                        parent: Arc::clone(&last.node),
115                        start_pos: last.range.end() + 1,
116                    },
117                    _ => SuggestionContext {
118                        parent: Arc::clone(&self.root),
119                        start_pos: self.range.start(),
120                    },
121                },
122            }
123        } else {
124            let mut prev = &self.root;
125            for node in &self.nodes {
126                if node.range.start() <= cursor && cursor <= node.range.end() {
127                    return SuggestionContext {
128                        parent: Arc::clone(prev),
129                        start_pos: node.range.start(),
130                    };
131                }
132                prev = &node.node;
133            }
134            SuggestionContext {
135                parent: Arc::clone(prev),
136                start_pos: self.range.start(),
137            }
138        }
139    }
140}
141
142impl<S> Debug for CommandContextBuilder<'_, S> {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        f.debug_struct("CommandContextBuilder")
145            // .field("arguments", &self.arguments)
146            .field("root", &self.root)
147            // .field("nodes", &self.nodes)
148            // .field("dispatcher", &self.dispatcher)
149            // .field("source", &self.source)
150            // .field("command", &self.command)
151            .field("child", &self.child)
152            .field("range", &self.range)
153            // .field("modifier", &self.modifier)
154            .field("forks", &self.forks)
155            .finish()
156    }
157}