1#[cfg(feature = "custom-commands")]
2#[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 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 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 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}