1use anyhow::Result;
4use clap::{builder::StyledStr, Command, CommandFactory, Parser};
5
6#[derive(Parser)]
8pub struct HelpCommand {
9 }
11
12pub struct HelpGenerator {
14 app: Command,
15}
16
17impl HelpGenerator {
18 pub fn new() -> Self {
20 use crate::cli::Cli;
21
22 let app = Cli::command();
24
25 Self { app }
26 }
27}
28
29impl Default for HelpGenerator {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl HelpGenerator {
36 pub fn generate_all_help(&self) -> Result<String> {
38 let mut help_sections = Vec::new();
39
40 let main_help = self.render_command_help(&self.app, "");
42 help_sections.push(main_help);
43
44 self.collect_help_recursive(&self.app, "", &mut help_sections);
46
47 let separator = format!("\n\n{}\n\n", "=".repeat(80));
49 Ok(help_sections.join(&separator))
50 }
51
52 fn collect_help_recursive(&self, cmd: &Command, prefix: &str, help_sections: &mut Vec<String>) {
62 let mut subcommands: Vec<_> = cmd.get_subcommands().collect();
64 subcommands.sort_by(|a, b| a.get_name().cmp(b.get_name()));
65
66 for subcmd in subcommands {
67 if subcmd.get_name() == "help" {
69 continue;
70 }
71
72 let current_path = if prefix.is_empty() {
73 subcmd.get_name().to_string()
74 } else {
75 format!("{} {}", prefix, subcmd.get_name())
76 };
77
78 let subcmd_help = self.render_command_help(subcmd, ¤t_path);
80 help_sections.push(subcmd_help);
81
82 self.collect_help_recursive(subcmd, ¤t_path, help_sections);
84 }
85 }
86
87 fn render_command_help(&self, cmd: &Command, path: &str) -> String {
89 let mut output = String::new();
90
91 let cmd_name = if path.is_empty() {
93 cmd.get_name().to_string()
94 } else {
95 format!("omni-dev {}", path)
96 };
97
98 let about = cmd
99 .get_about()
100 .map(|s| self.styled_str_to_string(s))
101 .unwrap_or_else(|| "No description available".to_string());
102
103 output.push_str(&format!("{} - {}\n\n", cmd_name, about));
104
105 let help_str = cmd.clone().render_help();
107 output.push_str(&help_str.to_string());
108
109 output
110 }
111
112 fn styled_str_to_string(&self, styled: &StyledStr) -> String {
114 styled.to_string()
115 }
116}
117
118impl HelpCommand {
119 pub fn execute(self) -> Result<()> {
121 let generator = HelpGenerator::new();
122 let help_output = generator.generate_all_help()?;
123 println!("{}", help_output);
124 Ok(())
125 }
126}