1use crate::router::CliRouter;
2use crate::CliCommand;
3use crate::*;
4use indexmap::{indexmap, IndexMap};
5
6pub struct CliHelpScreen {
7 pub title: String,
8 pub usage: String,
9 pub description: String,
10 pub params: IndexMap<String, String>,
11 pub flags: IndexMap<String, String>,
12 pub examples: Vec<String>,
13}
14
15impl CliHelpScreen {
16 pub fn new(title: &str, usage: &str, description: &str) -> Self {
17 Self {
18 title: title.to_string(),
19 usage: usage.to_string(),
20 description: description.to_string(),
21 params: indexmap![],
22 flags: indexmap![],
23 examples: Vec::new(),
24 }
25 }
26
27 pub fn add_param(&mut self, param: &str, description: &str) {
29 self.params
30 .insert(param.to_string(), description.to_string());
31 }
32
33 pub fn add_flag(&mut self, flag: &str, description: &str) {
35 self.flags.insert(flag.to_string(), description.to_string());
36 }
37
38 pub fn add_example(&mut self, example: &str) {
40 self.examples.push(example.to_string());
41 }
42
43 pub fn render(cmd: &Box<dyn CliCommand>, cmd_alias: &String, shortcuts: &Vec<String>) {
46 let help = cmd.help();
48
49 cli_header(help.title.as_str());
51 cli_send!("USAGE\r\n");
52 cli_send!(format!(" {}\r\n", help.usage).as_str());
53
54 for shortcut in shortcuts {
56 let tmp_usage = help.usage.replace(cmd_alias, shortcut.as_str());
57 cli_send!(format!(" {}\r\n", tmp_usage).as_str());
58 }
59 cli_send!("\r\n");
60
61 if !help.description.is_empty() {
63 let options = textwrap::Options::new(75)
64 .initial_indent(" ")
65 .subsequent_indent(" ");
66 let desc = textwrap::fill(help.description.as_str(), &options);
67
68 cli_send!("DESCRIPTION:\r\n\r\n");
69 cli_send!(desc.as_str());
70 cli_send!("\r\n\r\n");
71 }
72
73 if !help.params.is_empty() {
75 cli_send!("PARAMETERS\r\n\r\n");
76 cli_display_array(&help.params);
77 }
78
79 if !help.flags.is_empty() {
81 cli_send!("FLAGS\r\n\r\n");
82 cli_display_array(&help.flags);
83 }
84
85 if !help.examples.is_empty() {
87 cli_send!("EXAMPLES\r\n\r\n");
88 for example in help.examples {
89 println!(" {}\r\n", example);
90 }
91 }
92
93 cli_send!("-- END --\r\n\r\n");
95 }
96
97 pub fn render_index(router: &CliRouter) {
101 cli_header("Available Commands");
103 cli_send!("Below shows all available commands. Run any of the commands with 'help' as the first argument to view full details on the command.\r\n\r\n");
104 cli_send!("AVAILABLE COMMANDS\r\n\r\n");
105
106 let mut table: IndexMap<String, String> = indexmap![];
108 if !router.categories.is_empty() {
109 let mut keys: Vec<String> = router.categories.keys().cloned().collect();
112 keys.sort();
113
114 for alias in keys {
116 let (_title, description) = router.categories.get(&alias).unwrap();
117 table.insert(alias.to_string(), description.to_string());
118 }
119
120 cli_display_array(&table);
122
123 } else {
125 let mut keys: Vec<String> = router.commands.keys().cloned().collect();
127 keys.sort();
128
129 for alias in keys {
131 let cmd = router.commands.get(&alias).unwrap();
132 let cmd_help = cmd.help();
133 table.insert(alias.to_string(), cmd_help.description);
134 }
135
136 cli_display_array(&table);
138 }
139
140 cli_send!("-- END --\r\n");
142 std::process::exit(0);
143 }
144
145 pub fn render_category(router: &CliRouter, cat_alias: &String) {
149 let (cat_title, cat_desc) = router.categories.get(cat_alias).unwrap();
151 cli_header(cat_title);
152
153 if !cat_desc.is_empty() {
155 let options = textwrap::Options::new(75)
156 .initial_indent(" ")
157 .subsequent_indent(" ");
158 let desc = textwrap::fill(cat_desc.as_str(), &options);
159
160 cli_send!("DESCRIPTION:\r\n\r\n");
161 cli_send!(desc.as_str());
162 cli_send!("\r\n\r\n");
163 }
164
165 let chk = format!("{} ", cat_alias);
167 let mut sub_categories: Vec<String> = router
168 .categories
169 .keys()
170 .filter(|&k| k.starts_with(&chk))
171 .cloned()
172 .collect();
173 sub_categories.sort();
174
175 let mut table: IndexMap<String, String> = indexmap![];
177 for full_alias in sub_categories {
178 let alias = full_alias.trim_start_matches(&chk).to_string();
179 if alias.contains(" ") {
180 continue;
181 }
182 let (_, desc) = router.categories.get(&full_alias).unwrap();
183
184 table.insert(
185 alias,
186 desc.clone()
187 );
188 }
189
190 let mut keys: Vec<String> = router
192 .commands
193 .keys()
194 .filter(|&k| k.starts_with(&chk))
195 .cloned()
196 .collect();
197 keys.sort();
198
199 for full_alias in keys {
201 let alias = full_alias.trim_start_matches(&chk).to_string();
202 if alias.contains(" ") {
203 continue;
204 }
205 let cmd = router.commands.get(&full_alias).unwrap();
206 let cmd_help = cmd.help();
207 table.insert(
208 alias,
209 cmd_help.description,
210 );
211 }
212
213 cli_send!("AVAILABLE COMMANDS\r\n\r\n");
215 cli_display_array(&table);
216 cli_send!("-- END --\r\n\r\n");
217 std::process::exit(0);
218 }
219}