ricecoder_commands/
manager.rs1use crate::config::ConfigManager;
2use crate::error::Result;
3use crate::executor::CommandExecutor;
4use crate::output_injection::{OutputInjectionConfig, OutputInjector};
5use crate::registry::CommandRegistry;
6use crate::types::{CommandDefinition, CommandExecutionResult};
7use std::collections::HashMap;
8use std::path::Path;
9
10pub struct CommandManager {
12 registry: CommandRegistry,
13 output_config: OutputInjectionConfig,
14}
15
16impl CommandManager {
17 pub fn new(registry: CommandRegistry) -> Self {
19 Self {
20 registry,
21 output_config: OutputInjectionConfig::default(),
22 }
23 }
24
25 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
27 let registry = ConfigManager::load_from_file(path)?;
28 Ok(Self::new(registry))
29 }
30
31 pub fn set_output_config(&mut self, config: OutputInjectionConfig) {
33 self.output_config = config;
34 }
35
36 pub fn output_config(&self) -> &OutputInjectionConfig {
38 &self.output_config
39 }
40
41 pub fn registry(&self) -> &CommandRegistry {
43 &self.registry
44 }
45
46 pub fn registry_mut(&mut self) -> &mut CommandRegistry {
48 &mut self.registry
49 }
50
51 pub fn execute(
53 &self,
54 command_id: &str,
55 arguments: HashMap<String, String>,
56 cwd: String,
57 ) -> Result<CommandExecutionResult> {
58 let command = self.registry.get(command_id)?;
59
60 CommandExecutor::validate_arguments(&command, &arguments)?;
62
63 let context = CommandExecutor::build_context_with_defaults(&command, arguments, cwd)?;
65
66 CommandExecutor::execute(&command, &context)
68 }
69
70 pub fn execute_and_inject(
72 &self,
73 command_id: &str,
74 arguments: HashMap<String, String>,
75 cwd: String,
76 ) -> Result<String> {
77 let result = self.execute(command_id, arguments, cwd)?;
78 OutputInjector::inject(&result, &self.output_config)
79 }
80
81 pub fn list_commands(&self) -> Vec<CommandDefinition> {
83 self.registry.list_all()
84 }
85
86 pub fn list_enabled_commands(&self) -> Vec<CommandDefinition> {
88 self.registry.list_enabled()
89 }
90
91 pub fn get_command(&self, command_id: &str) -> Result<CommandDefinition> {
93 self.registry.get(command_id)
94 }
95
96 pub fn search_commands(&self, query: &str) -> Vec<CommandDefinition> {
98 self.registry.search(query)
99 }
100
101 pub fn find_commands_by_tag(&self, tag: &str) -> Vec<CommandDefinition> {
103 self.registry.find_by_tag(tag)
104 }
105
106 pub fn register_command(&mut self, command: CommandDefinition) -> Result<()> {
108 self.registry.register(command)
109 }
110
111 pub fn unregister_command(&mut self, command_id: &str) -> Result<()> {
113 self.registry.unregister(command_id)
114 }
115
116 pub fn enable_command(&mut self, command_id: &str) -> Result<()> {
118 self.registry.enable(command_id)
119 }
120
121 pub fn disable_command(&mut self, command_id: &str) -> Result<()> {
123 self.registry.disable(command_id)
124 }
125
126 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
128 ConfigManager::save_to_file(&self.registry, path)
129 }
130
131 pub fn reload_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
133 self.registry = ConfigManager::load_from_file(path)?;
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::types::{ArgumentType, CommandArgument};
142
143 fn create_test_manager() -> CommandManager {
144 let mut registry = CommandRegistry::new();
145 let cmd = CommandDefinition::new("test", "Test Command", "echo {{message}}")
146 .with_description("A test command")
147 .with_argument(
148 CommandArgument::new("message", ArgumentType::String)
149 .with_description("Message to echo")
150 .with_required(true),
151 );
152 registry.register(cmd).ok();
153 CommandManager::new(registry)
154 }
155
156 #[test]
157 fn test_list_commands() {
158 let manager = create_test_manager();
159 let commands = manager.list_commands();
160 assert_eq!(commands.len(), 1);
161 assert_eq!(commands[0].id, "test");
162 }
163
164 #[test]
165 fn test_get_command() {
166 let manager = create_test_manager();
167 let cmd = manager.get_command("test").unwrap();
168 assert_eq!(cmd.id, "test");
169 assert_eq!(cmd.name, "Test Command");
170 }
171
172 #[test]
173 fn test_search_commands() {
174 let manager = create_test_manager();
175 let results = manager.search_commands("test");
176 assert_eq!(results.len(), 1);
177 }
178
179 #[test]
180 fn test_register_command() {
181 let mut manager = create_test_manager();
182 let cmd = CommandDefinition::new("new-cmd", "New Command", "echo new");
183 assert!(manager.register_command(cmd).is_ok());
184 assert_eq!(manager.list_commands().len(), 2);
185 }
186
187 #[test]
188 fn test_unregister_command() {
189 let mut manager = create_test_manager();
190 assert!(manager.unregister_command("test").is_ok());
191 assert_eq!(manager.list_commands().len(), 0);
192 }
193
194 #[test]
195 fn test_enable_disable() {
196 let mut manager = create_test_manager();
197 assert!(manager.disable_command("test").is_ok());
198 assert_eq!(manager.list_enabled_commands().len(), 0);
199 assert!(manager.enable_command("test").is_ok());
200 assert_eq!(manager.list_enabled_commands().len(), 1);
201 }
202
203 #[test]
204 fn test_execute_command() {
205 let manager = create_test_manager();
206 let mut args = HashMap::new();
207 args.insert("message".to_string(), "Hello".to_string());
208
209 let result = manager.execute("test", args, ".".to_string()).unwrap();
210 assert!(result.success);
211 assert!(result.stdout.contains("Hello"));
212 }
213
214 #[test]
215 fn test_execute_missing_required_argument() {
216 let manager = create_test_manager();
217 let args = HashMap::new();
218 let result = manager.execute("test", args, ".".to_string());
219 assert!(result.is_err());
220 }
221
222 #[test]
223 fn test_execute_nonexistent_command() {
224 let manager = create_test_manager();
225 let args = HashMap::new();
226 let result = manager.execute("nonexistent", args, ".".to_string());
227 assert!(result.is_err());
228 }
229
230 #[test]
231 fn test_output_config() {
232 let mut manager = create_test_manager();
233 let config = OutputInjectionConfig {
234 inject_stdout: false,
235 ..Default::default()
236 };
237 manager.set_output_config(config);
238 assert!(!manager.output_config().inject_stdout);
239 }
240}