1use crate::command::Command;
2use crate::loader::CommandRegistry;
3use crate::output::hook;
4use crate::output::markdown;
5use crate::output::messages;
6
7pub struct HelpCommand;
9
10impl Default for HelpCommand {
11 fn default() -> Self {
12 Self::new()
13 }
14}
15
16impl HelpCommand {
17 pub fn new() -> Self {
18 Self
19 }
20}
21
22impl Command for HelpCommand {
23 fn name(&self) -> &str {
24 "help"
25 }
26
27 fn aliases(&self) -> &[&str] {
28 &["--help", "-h"]
29 }
30
31 fn help(&self) -> Option<&str> {
32 Some("Displays help information")
33 }
34
35 fn validate(&self, args: &[String]) -> Result<(), String> {
36 if args.len() > 1 {
37 Err("Too many arguments. Usage: help [command]".into())
38 } else {
39 Ok(())
40 }
41 }
42
43 fn execute(&self, _args: &[String]) {}
44
45 fn execute_with(&self, args: &[String], registry: &CommandRegistry) {
46 if args.len() == 1 {
48 let query = &args[0];
49 if let Some(target) = registry.get(query) {
51 if registry.is_visible(target) {
52 let name_line = target.name().to_string();
53 println!("{name_line}");
54 let body = target.help().unwrap_or("No description.");
55 let rendered = markdown::render_markdown(body);
56 print!("{rendered}");
57 } else {
58 println!("No help available for '{query}'");
59 }
60 return;
61 }
62
63 let ns = format!("{query}:");
65 let mut any = false;
66 let ns_header_fallback = format!("Help ({query}):");
67 let header = messages::message_or_default("help.ns_header", &ns_header_fallback);
68 println!("{header}");
69 for command in registry.all() {
70 let name = command.name();
71 if name.starts_with(&ns) && registry.is_visible(command.as_ref()) {
72 println!(
73 " {:<20} {}",
74 name,
75 markdown::render_markdown(command.help().unwrap_or("No description"))
76 );
77 any = true;
78 }
79 }
80 if !any {
81 let unknown =
82 format!("[{query}]. Type `help` or `--help` for a list of available commands.");
83 hook::unknown(&unknown);
84 }
85 return;
86 }
87
88 let header = messages::message_or_default("help.header", "Help:");
89 println!("{header}");
90 for command in registry.all() {
91 let name = command.name();
92 let top_level = !name.contains(':');
93 if top_level && registry.is_visible(command.as_ref()) {
94 println!(
95 " {:<12} {}",
96 name,
97 markdown::render_markdown(command.help().unwrap_or("No description"))
98 );
99 }
100 }
101 if let Some(footer) = messages::get_message("help.footer") {
102 println!("{footer}");
103 }
104 }
105}