1use std::collections::HashMap;
2use crate::command::Command;
3
4#[cfg(feature = "internal-commands")]
5use crate::commands::{PingCommand, EchoCommand, HelloCommand, HelpCommand};
6
7pub mod sources;
8
9use crate::loader::sources::CommandSource;
10
11pub struct CommandRegistry {
13 commands: HashMap<String, Box<dyn Command>>,
14}
15
16impl CommandRegistry {
17 pub fn new() -> Self {
19 let mut reg = Self {
20 commands: HashMap::new(),
21 };
22
23 #[cfg(feature = "internal-commands")]
24 reg.load_internal_commands();
25
26 reg
27 }
28
29 pub fn register(&mut self, cmd: Box<dyn Command>) {
31 self.commands.insert(cmd.name().to_string(), cmd);
32 }
33
34 pub fn execute(&self, cmd: &str, args: &[String]) {
36 if let Some(command) = self.commands.get(cmd) {
37 if command.name() == "help" {
38 if args.len() > 1 {
40 println!("Invalid usage: Too many arguments. Usage: help [command]");
41 return;
42 }
43
44 if args.len() == 1 {
45 let query = &args[0];
46 if let Some(target) = self.commands.get(query) {
47 if target.hidden() {
48 println!("No help available for '{}'", query);
49 } else {
50 println!(
51 "{} - {}",
52 target.name(),
53 target.help().unwrap_or("No description.")
54 );
55 }
56 } else {
57 println!("Unknown command: {}", query);
58 }
59 return;
60 }
61
62 println!("Help:");
63 for command in self.commands.values() {
64 if !command.hidden() {
65 println!(
66 " {:<12} {}",
67 command.name(),
68 command.help().unwrap_or("No description")
69 );
70 }
71 }
72 } else {
73 if let Err(err) = command.validate(args) {
75 eprintln!("Invalid usage: {}", err);
76 return;
77 }
78
79 command.execute(args);
80 }
81 } else {
82 eprintln!("Unknown command: {}", cmd);
83 }
84 }
85
86 #[cfg(feature = "internal-commands")]
88 pub fn load_internal_commands(&mut self) {
89 self.register(Box::new(PingCommand));
90 self.register(Box::new(EchoCommand));
91 self.register(Box::new(HelloCommand));
92 self.register(Box::new(HelpCommand::new()));
93 }
94
95 pub fn load_from(&mut self, source: Box<dyn CommandSource>) {
97 for cmd in source.load_commands() {
98 self.register(cmd);
99 }
100 }
101
102 pub fn len(&self) -> usize {
104 self.commands.len()
105 }
106}