1use crate::error::*;
2use crate::Parameter;
3use yansi::Paint;
4
5#[derive(Debug)]
8pub struct HelpEntry {
9 pub command: String,
11
12 pub aliases: Vec<String>,
14
15 pub parameters: Vec<(String, bool)>,
17
18 pub summary: Option<String>,
20}
21
22impl HelpEntry {
23 pub(crate) fn new(
24 command_name: &str,
25 aliases: &Vec<String>,
26 parameters: &[Parameter],
27 summary: &Option<String>,
28 ) -> Self {
29 Self {
30 command: command_name.to_string(),
31 aliases: aliases.clone(),
32 parameters: parameters
33 .iter()
34 .map(|pd| (pd.name.clone(), pd.required))
35 .collect(),
36 summary: summary.clone(),
37 }
38 }
39}
40
41pub struct HelpContext {
43 pub app_name: String,
45
46 pub app_version: String,
48
49 pub app_purpose: String,
51
52 pub help_entries: Vec<HelpEntry>,
54}
55
56impl HelpContext {
57 pub(crate) fn new(
58 app_name: &str,
59 app_version: &str,
60 app_purpose: &str,
61 help_entries: Vec<HelpEntry>,
62 ) -> Self {
63 Self {
64 app_name: app_name.into(),
65 app_version: app_version.into(),
66 app_purpose: app_purpose.into(),
67 help_entries,
68 }
69 }
70}
71
72pub trait HelpViewer {
74 fn help_general(&self, context: &HelpContext) -> Result<()>;
76
77 fn help_command(&self, entry: &HelpEntry) -> Result<()>;
80}
81
82pub struct DefaultHelpViewer;
84
85impl DefaultHelpViewer {
86 pub fn new() -> Self {
87 Self
88 }
89}
90
91impl HelpViewer for DefaultHelpViewer {
92 fn help_general(&self, context: &HelpContext) -> Result<()> {
93 self.print_help_header(context);
94 for entry in &context.help_entries {
95 print!("{}", entry.command);
96 if !entry.aliases.is_empty() {
97 print!(", {}", entry.aliases.join(", "));
98 }
99 if entry.summary.is_some() {
100 print!(" - {}", entry.summary.as_ref().unwrap());
101 }
102 println!();
103 }
104
105 Ok(())
106 }
107
108 fn help_command(&self, entry: &HelpEntry) -> Result<()> {
109 if entry.summary.is_some() {
110 println!("{}: {}", entry.command, entry.summary.as_ref().unwrap());
111 } else {
112 println!("{}:", entry.command);
113 }
114 if !entry.aliases.is_empty() {
115 println!("Aliases: {}", entry.aliases.join(", "));
116 }
117 println!("Usage:");
118 print!("\t{}", entry.command);
119 for param in &entry.parameters {
120 if param.1 {
121 print!(" {}", param.0);
122 } else {
123 print!(" [{}]", param.0);
124 }
125 }
126 println!();
127
128 Ok(())
129 }
130}
131
132impl DefaultHelpViewer {
133 fn print_help_header(&self, context: &HelpContext) {
134 let header = format!(
135 "{} {}: {}",
136 context.app_name, context.app_version, context.app_purpose
137 );
138 let underline = Paint::new(" ".repeat(header.len())).strikethrough();
139 println!("{}", header);
140 println!("{}", underline);
141 }
142}