modcli/
loader.rs

1#[cfg(feature = "custom-commands")]
2//pub mod custom;
3
4#[cfg(feature = "custom-commands")]
5use crate::custom::CustomCommand;
6
7#[cfg(feature = "plugins")]
8pub mod plugins;
9
10#[cfg(feature = "plugins")]
11use crate::loader::plugins::PluginLoader;
12
13#[cfg(feature = "internal-commands")]
14use crate::commands::{
15    PingCommand, 
16    EchoCommand, 
17    HelloCommand, 
18    HelpCommand, 
19    BenchmarkCommand
20};
21
22use std::collections::HashMap;
23use crate::command::Command;
24use crate::loader::sources::CommandSource;
25pub mod sources;
26
27pub struct CommandRegistry {
28    commands: HashMap<String, Box<dyn Command>>,
29}
30impl CommandRegistry {
31
32    /// Creates a new command registry
33    pub fn new() -> Self {
34        let mut reg = Self {
35            commands: HashMap::new(),
36        };
37
38        #[cfg(feature = "custom-commands")]
39        reg.load_custom_commands();
40
41        #[cfg(feature = "internal-commands")]
42        reg.load_internal_commands();
43
44        reg
45    }
46
47 
48    pub fn get(&self, name: &str) -> Option<&Box<dyn Command>> {
49        self.commands.get(name)
50    }
51
52 
53    pub fn register(&mut self, cmd: Box<dyn Command>) {
54        self.commands.insert(cmd.name().to_string(), cmd);
55    }
56
57 
58    #[cfg(feature = "plugins")]
59    pub fn load_plugins(&mut self, path: &str) {
60        let loader = PluginLoader::new(path);
61        for plugin in loader.load_plugins() {
62            self.register(plugin);
63        }
64    }
65
66    pub fn execute(&self, cmd: &str, args: &[String]) {
67        if let Some(command) = self.commands.get(cmd) {
68            if command.name() == "help" {
69                // Special case for help: render help output with registry context
70                if args.len() > 1 {
71                    println!("Invalid usage: Too many arguments. Usage: help [command]");
72                    return;
73                }
74
75                if args.len() == 1 {
76                    let query = &args[0];
77                    if let Some(target) = self.commands.get(query) {
78                        if target.hidden() {
79                            println!("No help available for '{}'", query);
80                        } else {
81                            println!(
82                                "{} - {}",
83                                target.name(),
84                                target.help().unwrap_or("No description.")
85                            );
86                        }
87                    } else {
88                        println!("Unknown command: {}", query);
89                    }
90                    return;
91                }
92
93                println!("Help:");
94                for command in self.commands.values() {
95                    if !command.hidden() {
96                        println!(
97                            "  {:<12} {}",
98                            command.name(),
99                            command.help().unwrap_or("No description")
100                        );
101                    }
102                }
103            } else {
104                // Normal command execution
105                if let Err(err) = command.validate(args) {
106                    eprintln!("Invalid usage: {}", err);
107                    return;
108                }
109
110                command.execute(args);
111            }
112        } else {
113            eprintln!("Unknown command: {}", cmd);
114        }
115    }
116
117
118    #[cfg(feature = "internal-commands")]
119    pub fn load_internal_commands(&mut self) {
120        self.register(Box::new(PingCommand));
121        self.register(Box::new(EchoCommand));
122        self.register(Box::new(HelloCommand));
123        self.register(Box::new(HelpCommand::new()));
124        self.register(Box::new(BenchmarkCommand::new()));
125    }
126
127
128
129    pub fn load_from(&mut self, source: Box<dyn CommandSource>) {
130        for cmd in source.load_commands() {
131            self.register(cmd);
132        }
133    }
134
135
136    pub fn len(&self) -> usize {
137        self.commands.len()
138    }
139
140    #[cfg(feature = "custom-commands")]
141    pub fn load_custom_commands(&mut self) {
142        self.register(Box::new(CustomCommand));
143    }
144
145}