1use crate::{Group, option, arg};
2use std::rc::Rc;
3
4pub struct HelpEntry<K, V> {
6 pub key: K,
7 pub value: V,
8}
9
10pub trait HelpPrinter {
12 fn print(
14 &self,
15 group: &Group,
16 subcommand_entries: &Vec<HelpEntry<&Rc<String>, &Rc<Group>>>,
17 option_entries: &Vec<HelpEntry<&Rc<String>, &Rc<option::Descriptor>>>,
18 arg_entries: &Vec<arg::Descriptor>,
19 );
20}
21
22pub struct DefaultHelpPrinter {}
24
25impl HelpPrinter for DefaultHelpPrinter {
26 fn print(
27 &self,
28 group: &Group,
29 subcommand_entries: &Vec<HelpEntry<&Rc<String>, &Rc<Group>>>,
30 option_entries: &Vec<HelpEntry<&Rc<String>, &Rc<option::Descriptor>>>,
31 arg_entries: &Vec<arg::Descriptor>,
32 ) {
33 println!("\n### DESCRIPTION ###");
34 println!("{description}", description = group.description());
35
36 println!("\n### SUB-COMMANDS ###");
37 if subcommand_entries.len() == 0 {
38 println!("(No sub-commands available...)");
39 } else {
40 let mut max_length = 0;
42 for entry in subcommand_entries {
43 let prefix = match group.get_aliases_for_group_name(&entry.key) {
44 Some(aliases) => format!(
45 "{name} ({aliases})",
46 name = entry.key,
47 aliases = aliases.iter().map(|s| s.as_ref().to_string()).collect::<Vec<String>>().join(", ")
48 ),
49 None => entry.key.to_string(),
50 };
51 if prefix.len() > max_length {
52 max_length = prefix.len();
53 }
54 }
55
56 for entry in subcommand_entries {
57 let prefix = match group.get_aliases_for_group_name(&entry.key) {
58 Some(aliases) => format!(
59 "{name} ({aliases})",
60 name = entry.key,
61 aliases = aliases.iter().map(|s| s.as_ref().to_string()).collect::<Vec<String>>().join(", ")
62 ),
63 None => entry.key.to_string(),
64 };
65 println!(" - {prefix:<width$} | {description}", prefix = prefix, width = max_length, description = entry.value.description());
66 }
67 }
68
69 println!("\n### OPTIONS ###");
70 if option_entries.len() == 0 {
71 println!("(No options available...)");
72 } else {
73 let mut max_length = 0;
75 for entry in option_entries {
76 let aliases = entry.value.get_aliases();
77 let prefix = if aliases.len() == 0 {
78 format!("{name} <{type_name}>", name = entry.key, type_name = entry.value.value_type())
79 } else {
80 format!(
81 "{name} ({aliases}) <{type_name}>",
82 name = entry.key,
83 aliases = aliases.iter().map(|s| format!("-{}", s)).collect::<Vec<String>>().join(", "),
84 type_name = entry.value.value_type()
85 )
86 };
87 if prefix.len() > max_length {
88 max_length = prefix.len();
89 }
90 }
91
92 for entry in option_entries {
93 let aliases = entry.value.get_aliases();
94 let prefix = if aliases.len() == 0 {
95 format!("{name} <{type_name}>", name = entry.key, type_name = entry.value.value_type())
96 } else {
97 format!(
98 "{name} ({aliases}) <{type_name}>",
99 name = entry.key,
100 aliases = aliases.iter().map(|s| format!("-{}", s)).collect::<Vec<String>>().join(", "),
101 type_name = entry.value.value_type()
102 )
103 };
104 println!(" --{prefix:<width$} | {description}", prefix = prefix, width = max_length, description = entry.value.description());
105 }
106 }
107
108 println!("\n### ARGUMENTS ###");
109 if arg_entries.len() == 0 {
110 println!("(Command expects no arguments...)");
111 } else {
112 let mut max_length = 0;
113 for i in 0..arg_entries.len() {
114 let arg_d = &arg_entries[i];
115
116 let prefix = format!("{num}. <{type_name}>", num = i + 1, type_name = arg_d.value_type());
117 if prefix.len() > max_length {
118 max_length = prefix.len();
119 }
120 }
121
122 for i in 0..arg_entries.len() {
123 let arg_d = &arg_entries[i];
124
125 let prefix = format!("{num}. <{type_name}>", num = i + 1, type_name = arg_d.value_type());
126 println!(" {prefix:<width$} | {description}", prefix = prefix, width = max_length, description = arg_d.description());
127 }
128 }
129
130 println!();
131 }
132}