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