ricecoder_commands/
registry.rs1use crate::error::{CommandError, Result};
2use crate::types::CommandDefinition;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
7pub struct CommandRegistry {
8 commands: HashMap<String, CommandDefinition>,
9}
10
11impl CommandRegistry {
12 pub fn new() -> Self {
14 Self {
15 commands: HashMap::new(),
16 }
17 }
18
19 pub fn register(&mut self, command: CommandDefinition) -> Result<()> {
21 if command.id.is_empty() {
22 return Err(CommandError::InvalidCommandName(
23 "Command ID cannot be empty".to_string(),
24 ));
25 }
26
27 if self.commands.contains_key(&command.id) {
28 return Err(CommandError::InvalidCommandName(format!(
29 "Command already registered: {}",
30 command.id
31 )));
32 }
33
34 self.commands.insert(command.id.clone(), command);
35 Ok(())
36 }
37
38 pub fn unregister(&mut self, command_id: &str) -> Result<()> {
40 self.commands
41 .remove(command_id)
42 .ok_or_else(|| CommandError::CommandNotFound(command_id.to_string()))?;
43 Ok(())
44 }
45
46 pub fn get(&self, command_id: &str) -> Result<CommandDefinition> {
48 self.commands
49 .get(command_id)
50 .cloned()
51 .ok_or_else(|| CommandError::CommandNotFound(command_id.to_string()))
52 }
53
54 pub fn list_all(&self) -> Vec<CommandDefinition> {
56 self.commands.values().cloned().collect()
57 }
58
59 pub fn list_enabled(&self) -> Vec<CommandDefinition> {
61 self.commands
62 .values()
63 .filter(|cmd| cmd.enabled)
64 .cloned()
65 .collect()
66 }
67
68 pub fn find_by_tag(&self, tag: &str) -> Vec<CommandDefinition> {
70 self.commands
71 .values()
72 .filter(|cmd| cmd.tags.contains(&tag.to_string()))
73 .cloned()
74 .collect()
75 }
76
77 pub fn search(&self, query: &str) -> Vec<CommandDefinition> {
79 let query_lower = query.to_lowercase();
80 self.commands
81 .values()
82 .filter(|cmd| {
83 cmd.name.to_lowercase().contains(&query_lower)
84 || cmd.description.to_lowercase().contains(&query_lower)
85 })
86 .cloned()
87 .collect()
88 }
89
90 pub fn enable(&mut self, command_id: &str) -> Result<()> {
92 let command = self
93 .commands
94 .get_mut(command_id)
95 .ok_or_else(|| CommandError::CommandNotFound(command_id.to_string()))?;
96 command.enabled = true;
97 Ok(())
98 }
99
100 pub fn disable(&mut self, command_id: &str) -> Result<()> {
102 let command = self
103 .commands
104 .get_mut(command_id)
105 .ok_or_else(|| CommandError::CommandNotFound(command_id.to_string()))?;
106 command.enabled = false;
107 Ok(())
108 }
109
110 pub fn exists(&self, command_id: &str) -> bool {
112 self.commands.contains_key(command_id)
113 }
114
115 pub fn count(&self) -> usize {
117 self.commands.len()
118 }
119
120 pub fn clear(&mut self) {
122 self.commands.clear();
123 }
124}
125
126impl Default for CommandRegistry {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_register_command() {
138 let mut registry = CommandRegistry::new();
139 let cmd = CommandDefinition::new("test", "Test", "echo test");
140 assert!(registry.register(cmd).is_ok());
141 assert_eq!(registry.count(), 1);
142 }
143
144 #[test]
145 fn test_register_duplicate_command() {
146 let mut registry = CommandRegistry::new();
147 let cmd1 = CommandDefinition::new("test", "Test", "echo test");
148 let cmd2 = CommandDefinition::new("test", "Test", "echo test");
149 assert!(registry.register(cmd1).is_ok());
150 assert!(registry.register(cmd2).is_err());
151 }
152
153 #[test]
154 fn test_get_command() {
155 let mut registry = CommandRegistry::new();
156 let cmd = CommandDefinition::new("test", "Test", "echo test");
157 registry.register(cmd).unwrap();
158 let retrieved = registry.get("test").unwrap();
159 assert_eq!(retrieved.id, "test");
160 }
161
162 #[test]
163 fn test_get_nonexistent_command() {
164 let registry = CommandRegistry::new();
165 assert!(registry.get("nonexistent").is_err());
166 }
167
168 #[test]
169 fn test_unregister_command() {
170 let mut registry = CommandRegistry::new();
171 let cmd = CommandDefinition::new("test", "Test", "echo test");
172 registry.register(cmd).unwrap();
173 assert!(registry.unregister("test").is_ok());
174 assert_eq!(registry.count(), 0);
175 }
176
177 #[test]
178 fn test_list_all_commands() {
179 let mut registry = CommandRegistry::new();
180 registry
181 .register(CommandDefinition::new("cmd1", "Cmd1", "echo 1"))
182 .ok();
183 registry
184 .register(CommandDefinition::new("cmd2", "Cmd2", "echo 2"))
185 .ok();
186 assert_eq!(registry.list_all().len(), 2);
187 }
188
189 #[test]
190 fn test_list_enabled_commands() {
191 let mut registry = CommandRegistry::new();
192 let cmd1 = CommandDefinition::new("cmd1", "Cmd1", "echo 1");
193 let mut cmd2 = CommandDefinition::new("cmd2", "Cmd2", "echo 2");
194 cmd2.enabled = false;
195 registry.register(cmd1).ok();
196 registry.register(cmd2).ok();
197 assert_eq!(registry.list_enabled().len(), 1);
198 }
199
200 #[test]
201 fn test_find_by_tag() {
202 let mut registry = CommandRegistry::new();
203 let cmd1 = CommandDefinition::new("cmd1", "Cmd1", "echo 1").with_tag("test");
204 let cmd2 = CommandDefinition::new("cmd2", "Cmd2", "echo 2").with_tag("prod");
205 registry.register(cmd1).ok();
206 registry.register(cmd2).ok();
207 assert_eq!(registry.find_by_tag("test").len(), 1);
208 }
209
210 #[test]
211 fn test_search_commands() {
212 let mut registry = CommandRegistry::new();
213 let cmd1 = CommandDefinition::new("cmd1", "Test Command", "echo 1");
214 let cmd2 = CommandDefinition::new("cmd2", "Other", "echo 2");
215 registry.register(cmd1).ok();
216 registry.register(cmd2).ok();
217 assert_eq!(registry.search("test").len(), 1);
218 }
219
220 #[test]
221 fn test_enable_disable() {
222 let mut registry = CommandRegistry::new();
223 let cmd = CommandDefinition::new("test", "Test", "echo test");
224 registry.register(cmd).ok();
225 registry.disable("test").ok();
226 assert!(!registry.get("test").unwrap().enabled);
227 registry.enable("test").ok();
228 assert!(registry.get("test").unwrap().enabled);
229 }
230}