1 // Std
2 use std::{
3     borrow::Cow,
4     cmp,
5     collections::BTreeMap,
6     io::{self, Write},
7     usize,
8 };
9 
10 // Internal
11 use crate::{
12     build::{App, AppSettings, Arg, ArgSettings},
13     output::{fmt::Colorizer, Usage},
14     parse::Parser,
15     util::VecMap,
16     INTERNAL_ERROR_MSG,
17 };
18 
19 // Third party
20 use indexmap::IndexSet;
21 use unicode_width::UnicodeWidthStr;
22 
dimensions() -> Option<(usize, usize)>23 pub(crate) fn dimensions() -> Option<(usize, usize)> {
24     #[cfg(not(feature = "wrap_help"))]
25     return None;
26 
27     #[cfg(feature = "wrap_help")]
28     terminal_size::terminal_size().map(|(w, h)| (w.0.into(), h.0.into()))
29 }
30 
str_width(s: &str) -> usize31 fn str_width(s: &str) -> usize {
32     UnicodeWidthStr::width(s)
33 }
34 
35 const TAB: &str = "    ";
36 
37 pub(crate) enum HelpWriter<'writer> {
38     Normal(&'writer mut dyn Write),
39     Buffer(&'writer mut Colorizer),
40 }
41 
42 /// `clap` Help Writer.
43 ///
44 /// Wraps a writer stream providing different methods to generate help for `clap` objects.
45 pub(crate) struct Help<'help, 'app, 'parser, 'writer> {
46     writer: HelpWriter<'writer>,
47     parser: &'parser Parser<'help, 'app>,
48     next_line_help: bool,
49     hide_pv: bool,
50     term_w: usize,
51     longest: usize,
52     force_next_line: bool,
53     use_long: bool,
54 }
55 
56 // Public Functions
57 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
58     const DEFAULT_TEMPLATE: &'static str = "\
59         {before-help}{bin} {version}\n\
60         {author-with-newline}{about-with-newline}\n\
61         {usage-heading}\n    {usage}\n\
62         \n\
63         {all-args}{after-help}\
64     ";
65 
66     const DEFAULT_NO_ARGS_TEMPLATE: &'static str = "\
67         {before-help}{bin} {version}\n\
68         {author-with-newline}{about-with-newline}\n\
69         {usage-heading}\n    {usage}{after-help}\
70     ";
71 
72     /// Create a new `Help` instance.
new( w: HelpWriter<'writer>, parser: &'parser Parser<'help, 'app>, use_long: bool, ) -> Self73     pub(crate) fn new(
74         w: HelpWriter<'writer>,
75         parser: &'parser Parser<'help, 'app>,
76         use_long: bool,
77     ) -> Self {
78         debug!("Help::new");
79         let term_w = match parser.app.term_w {
80             Some(0) => usize::MAX,
81             Some(w) => w,
82             None => cmp::min(
83                 dimensions().map_or(100, |(w, _)| w),
84                 match parser.app.max_w {
85                     None | Some(0) => usize::MAX,
86                     Some(mw) => mw,
87                 },
88             ),
89         };
90         let nlh = parser.is_set(AppSettings::NextLineHelp);
91         let hide_pv = parser.is_set(AppSettings::HidePossibleValuesInHelp);
92 
93         Help {
94             writer: w,
95             parser,
96             next_line_help: nlh,
97             hide_pv,
98             term_w,
99             longest: 0,
100             force_next_line: false,
101             use_long,
102         }
103     }
104 
105     /// Writes the parser help to the wrapped stream.
write_help(&mut self) -> io::Result<()>106     pub(crate) fn write_help(&mut self) -> io::Result<()> {
107         debug!("Help::write_help");
108 
109         if let Some(h) = self.parser.app.help_str {
110             self.none(h)?;
111         } else if let Some(tmpl) = self.parser.app.template {
112             self.write_templated_help(tmpl)?;
113         } else {
114             let flags = self.parser.has_flags();
115             let pos = self.parser.has_positionals();
116             let opts = self.parser.has_opts();
117             let subcmds = self.parser.has_subcommands();
118 
119             if flags || opts || pos || subcmds {
120                 self.write_templated_help(Self::DEFAULT_TEMPLATE)?;
121             } else {
122                 self.write_templated_help(Self::DEFAULT_NO_ARGS_TEMPLATE)?;
123             }
124         }
125 
126         self.none("\n")?;
127 
128         Ok(())
129     }
130 }
131 
132 macro_rules! write_method {
133     ($_self:ident, $msg:ident, $meth:ident) => {
134         match &mut $_self.writer {
135             HelpWriter::Buffer(c) => {
136                 c.$meth(($msg).into());
137                 Ok(())
138             }
139             HelpWriter::Normal(w) => w.write_all($msg.as_ref()),
140         }
141     };
142 }
143 
144 macro_rules! write_nspaces {
145     ($_self:ident, $num:expr) => {{
146         debug!("Help::write_nspaces!: num={}", $num);
147         for _ in 0..$num {
148             $_self.none(" ")?;
149         }
150     }};
151 }
152 
153 // Methods to write Arg help.
154 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
good<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()>155     fn good<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
156         write_method!(self, msg, good)
157     }
158 
warning<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()>159     fn warning<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
160         write_method!(self, msg, warning)
161     }
162 
none<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()>163     fn none<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
164         write_method!(self, msg, none)
165     }
166 
167     /// Writes help for each argument in the order they were declared to the wrapped stream.
write_args_unsorted(&mut self, args: &[&Arg<'help>]) -> io::Result<()>168     fn write_args_unsorted(&mut self, args: &[&Arg<'help>]) -> io::Result<()> {
169         debug!("Help::write_args_unsorted");
170         // The shortest an arg can legally be is 2 (i.e. '-x')
171         self.longest = 2;
172         let mut arg_v = Vec::with_capacity(10);
173         let use_long = self.use_long;
174         for arg in args.iter().filter(|arg| should_show_arg(use_long, *arg)) {
175             if arg.longest_filter() {
176                 self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
177             }
178             arg_v.push(arg)
179         }
180         let mut first = true;
181         let arg_c = arg_v.len();
182         for (i, arg) in arg_v.iter().enumerate() {
183             if first {
184                 first = false;
185             } else {
186                 self.none("\n")?;
187             }
188             self.write_arg(arg, i < arg_c)?;
189         }
190         Ok(())
191     }
192 
193     /// Sorts arguments by length and display order and write their help to the wrapped stream.
write_args(&mut self, args: &[&Arg<'help>]) -> io::Result<()>194     fn write_args(&mut self, args: &[&Arg<'help>]) -> io::Result<()> {
195         debug!("Help::write_args");
196         // The shortest an arg can legally be is 2 (i.e. '-x')
197         self.longest = 2;
198         let mut ord_m = VecMap::new();
199         let use_long = self.use_long;
200         // Determine the longest
201         for arg in args.iter().filter(|arg| {
202             // If it's NextLineHelp we don't care to compute how long it is because it may be
203             // NextLineHelp on purpose simply *because* it's so long and would throw off all other
204             // args alignment
205             should_show_arg(use_long, *arg)
206         }) {
207             if arg.longest_filter() {
208                 debug!("Help::write_args: Current Longest...{}", self.longest);
209                 self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
210                 debug!("Help::write_args: New Longest...{}", self.longest);
211             }
212             let btm = ord_m.entry(arg.disp_ord).or_insert(BTreeMap::new());
213             // We use name here for alphabetic sorting
214             // @TODO @maybe perhaps we could do some sort of ordering off of keys?
215             btm.insert(arg.name, arg);
216         }
217         let mut first = true;
218         for btm in ord_m.values() {
219             for arg in btm.values() {
220                 if first {
221                     first = false;
222                 } else {
223                     self.none("\n")?;
224                 }
225                 self.write_arg(arg, false)?;
226             }
227         }
228         Ok(())
229     }
230 
231     /// Writes help for an argument to the wrapped stream.
write_arg(&mut self, arg: &Arg<'help>, prevent_nlh: bool) -> io::Result<()>232     fn write_arg(&mut self, arg: &Arg<'help>, prevent_nlh: bool) -> io::Result<()> {
233         debug!("Help::write_arg");
234         self.short(arg)?;
235         self.long(arg)?;
236         let spec_vals = self.val(arg)?;
237         self.help(arg, &*spec_vals, prevent_nlh)?;
238         Ok(())
239     }
240 
241     /// Writes argument's short command to the wrapped stream.
short(&mut self, arg: &Arg<'help>) -> io::Result<()>242     fn short(&mut self, arg: &Arg<'help>) -> io::Result<()> {
243         debug!("Help::short");
244 
245         self.none(TAB)?;
246 
247         if let Some(s) = arg.short {
248             self.good(&format!("-{}", s))
249         } else if arg.has_switch() {
250             self.none(TAB)
251         } else {
252             Ok(())
253         }
254     }
255 
256     /// Writes argument's long command to the wrapped stream.
long(&mut self, arg: &Arg<'help>) -> io::Result<()>257     fn long(&mut self, arg: &Arg<'help>) -> io::Result<()> {
258         debug!("Help::long");
259         if !arg.has_switch() {
260             return Ok(());
261         }
262         if arg.is_set(ArgSettings::TakesValue) {
263             if let Some(l) = arg.long {
264                 if arg.short.is_some() {
265                     self.none(", ")?;
266                 }
267                 self.good(&format!("--{}", l))?
268             }
269 
270             let sep = if arg.is_set(ArgSettings::RequireEquals) {
271                 "="
272             } else {
273                 " "
274             };
275             self.none(sep)?;
276         } else if let Some(l) = arg.long {
277             if arg.short.is_some() {
278                 self.none(", ")?;
279             }
280             self.good(&format!("--{}", l))?;
281         }
282         Ok(())
283     }
284 
285     /// Writes argument's possible values to the wrapped stream.
val(&mut self, arg: &Arg) -> Result<String, io::Error>286     fn val(&mut self, arg: &Arg) -> Result<String, io::Error> {
287         debug!("Help::val: arg={}", arg.name);
288         let mult =
289             arg.is_set(ArgSettings::MultipleValues) || arg.is_set(ArgSettings::MultipleOccurrences);
290         if arg.is_set(ArgSettings::TakesValue) || arg.index.is_some() {
291             let delim = if arg.is_set(ArgSettings::RequireDelimiter) {
292                 arg.val_delim.expect(INTERNAL_ERROR_MSG)
293             } else {
294                 ' '
295             };
296             if !arg.val_names.is_empty() {
297                 let mut it = arg.val_names.iter().peekable();
298                 while let Some((_, val)) = it.next() {
299                     self.good(&format!("<{}>", val))?;
300                     if it.peek().is_some() {
301                         self.none(&delim.to_string())?;
302                     }
303                 }
304                 let num = arg.val_names.len();
305                 if mult && num == 1 {
306                     self.good("...")?;
307                 }
308             } else if let Some(num) = arg.num_vals {
309                 let mut it = (0..num).peekable();
310                 while let Some(_) = it.next() {
311                     self.good(&format!("<{}>", arg.name))?;
312                     if it.peek().is_some() {
313                         self.none(&delim.to_string())?;
314                     }
315                 }
316                 if mult && num == 1 {
317                     self.good("...")?;
318                 }
319             } else if arg.has_switch() {
320                 self.good(&format!("<{}>", arg.name))?;
321                 if mult {
322                     self.good("...")?;
323                 }
324             } else {
325                 self.good(&arg.to_string())?;
326             }
327         }
328 
329         let spec_vals = self.spec_vals(arg);
330         let h = arg.about.unwrap_or("");
331         let h_w = str_width(h) + str_width(&*spec_vals);
332         let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
333         let taken = self.longest + 12;
334         self.force_next_line = !nlh
335             && self.term_w >= taken
336             && (taken as f32 / self.term_w as f32) > 0.40
337             && h_w > (self.term_w - taken);
338 
339         debug!("Help::val: Has switch...");
340         if self.use_long {
341             // long help prints messages on the next line so it don't need to align text
342             debug!("Help::val: printing long help so skip aligment");
343         } else if arg.has_switch() {
344             debug!("Yes");
345             debug!("Help::val: force_next_line...{:?}", self.force_next_line);
346             debug!("Help::val: nlh...{:?}", nlh);
347             debug!("Help::val: taken...{}", taken);
348             debug!(
349                 "val: help_width > (width - taken)...{} > ({} - {})",
350                 h_w, self.term_w, taken
351             );
352             debug!("Help::val: longest...{}", self.longest);
353             debug!("Help::val: next_line...");
354             if !(nlh || self.force_next_line) {
355                 debug!("No");
356                 let self_len = str_width(arg.to_string().as_str());
357                 // subtract ourself
358                 let mut spcs = self.longest - self_len;
359                 // Since we're writing spaces from the tab point we first need to know if we
360                 // had a long and short, or just short
361                 if arg.long.is_some() {
362                     // Only account 4 after the val
363                     spcs += 4;
364                 } else {
365                     // Only account for ', --' + 4 after the val
366                     spcs += 8;
367                 }
368 
369                 write_nspaces!(self, spcs);
370             } else {
371                 debug!("Yes");
372             }
373         } else if !(nlh || self.force_next_line) {
374             debug!("No, and not next_line");
375             write_nspaces!(
376                 self,
377                 self.longest + 4 - (str_width(arg.to_string().as_str()))
378             );
379         } else {
380             debug!("No");
381         }
382         Ok(spec_vals)
383     }
384 
write_before_after_help(&mut self, h: &str) -> io::Result<()>385     fn write_before_after_help(&mut self, h: &str) -> io::Result<()> {
386         debug!("Help::write_before_after_help");
387         let mut help = String::from(h);
388         // determine if our help fits or needs to wrap
389         debug!(
390             "Help::write_before_after_help: Term width...{}",
391             self.term_w
392         );
393         let too_long = str_width(h) >= self.term_w;
394 
395         debug!("Help::write_before_after_help: Too long...");
396         if too_long {
397             debug!("Yes");
398             debug!("Help::write_before_after_help: help: {}", help);
399             debug!(
400                 "Help::write_before_after_help: help width: {}",
401                 str_width(&*help)
402             );
403             // Determine how many newlines we need to insert
404             debug!(
405                 "Help::write_before_after_help: Usable space: {}",
406                 self.term_w
407             );
408             help = wrap_help(&help, self.term_w);
409         } else {
410             debug!("No");
411         }
412         self.none(&help)?;
413         Ok(())
414     }
415 
416     /// Writes argument's help to the wrapped stream.
help(&mut self, arg: &Arg, spec_vals: &str, prevent_nlh: bool) -> io::Result<()>417     fn help(&mut self, arg: &Arg, spec_vals: &str, prevent_nlh: bool) -> io::Result<()> {
418         debug!("Help::help");
419         let h = if self.use_long {
420             arg.long_about.unwrap_or_else(|| arg.about.unwrap_or(""))
421         } else {
422             arg.about.unwrap_or_else(|| arg.long_about.unwrap_or(""))
423         };
424         let mut help = String::from(h) + spec_vals;
425         let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
426         debug!("Help::help: Next Line...{:?}", nlh);
427 
428         let spcs = if nlh || self.force_next_line {
429             12 // "tab" * 3
430         } else {
431             self.longest + 12
432         };
433 
434         let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
435 
436         // Is help on next line, if so then indent
437         if nlh || self.force_next_line {
438             self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
439         }
440 
441         debug!("Help::help: Too long...");
442         if too_long && spcs <= self.term_w {
443             debug!("Yes");
444             debug!("Help::help: help...{}", help);
445             debug!("Help::help: help width...{}", str_width(&*help));
446             // Determine how many newlines we need to insert
447             let avail_chars = self.term_w - spcs;
448             debug!("Help::help: Usable space...{}", avail_chars);
449             help = wrap_help(&help, avail_chars);
450         } else {
451             debug!("No");
452         }
453         if let Some(part) = help.lines().next() {
454             self.none(part)?;
455         }
456         for part in help.lines().skip(1) {
457             self.none("\n")?;
458             if nlh || self.force_next_line {
459                 self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
460             } else if arg.has_switch() {
461                 write_nspaces!(self, self.longest + 12);
462             } else {
463                 write_nspaces!(self, self.longest + 8);
464             }
465             self.none(part)?;
466         }
467         if !prevent_nlh && (nlh || self.force_next_line) {
468             self.none("\n")?;
469         }
470         Ok(())
471     }
472 
spec_vals(&self, a: &Arg) -> String473     fn spec_vals(&self, a: &Arg) -> String {
474         debug!("Help::spec_vals: a={}", a);
475         let mut spec_vals = vec![];
476         if let Some(ref env) = a.env {
477             debug!(
478                 "Help::spec_vals: Found environment variable...[{:?}:{:?}]",
479                 env.0, env.1
480             );
481             let env_val = if !a.is_set(ArgSettings::HideEnvValues) {
482                 format!(
483                     "={}",
484                     env.1
485                         .as_ref()
486                         .map_or(Cow::Borrowed(""), |val| val.to_string_lossy())
487                 )
488             } else {
489                 String::new()
490             };
491             let env_info = format!("[env: {}{}]", env.0.to_string_lossy(), env_val);
492             spec_vals.push(env_info);
493         }
494         if !a.is_set(ArgSettings::HideDefaultValue) && !a.default_vals.is_empty() {
495             debug!(
496                 "Help::spec_vals: Found default value...[{:?}]",
497                 a.default_vals
498             );
499 
500             let pvs = a
501                 .default_vals
502                 .iter()
503                 .map(|&pvs| pvs.to_string_lossy())
504                 .collect::<Vec<_>>()
505                 .join(" ");
506 
507             spec_vals.push(format!("[default: {}]", pvs));
508         }
509         if !a.aliases.is_empty() {
510             debug!("Help::spec_vals: Found aliases...{:?}", a.aliases);
511 
512             let als = a
513                 .aliases
514                 .iter()
515                 .filter(|&als| als.1) // visible
516                 .map(|&als| als.0) // name
517                 .collect::<Vec<_>>()
518                 .join(", ");
519 
520             if !als.is_empty() {
521                 spec_vals.push(format!("[aliases: {}]", als));
522             }
523         }
524 
525         if !a.short_aliases.is_empty() {
526             debug!(
527                 "Help::spec_vals: Found short aliases...{:?}",
528                 a.short_aliases
529             );
530 
531             let als = a
532                 .short_aliases
533                 .iter()
534                 .filter(|&als| als.1) // visible
535                 .map(|&als| als.0.to_string()) // name
536                 .collect::<Vec<_>>()
537                 .join(", ");
538 
539             if !als.is_empty() {
540                 spec_vals.push(format!("[short aliases: {}]", als));
541             }
542         }
543 
544         if !self.hide_pv
545             && !a.is_set(ArgSettings::HidePossibleValues)
546             && !a.possible_vals.is_empty()
547         {
548             debug!(
549                 "Help::spec_vals: Found possible vals...{:?}",
550                 a.possible_vals
551             );
552 
553             spec_vals.push(format!("[possible values: {}]", a.possible_vals.join(", ")));
554         }
555         let prefix = if !spec_vals.is_empty() && !a.get_about().unwrap_or("").is_empty() {
556             " "
557         } else {
558             ""
559         };
560         prefix.to_string() + &spec_vals.join(" ")
561     }
562 }
563 
564 /// Methods to write a single subcommand
565 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
write_subcommand(&mut self, sc_str: &str, app: &App<'help>) -> io::Result<()>566     fn write_subcommand(&mut self, sc_str: &str, app: &App<'help>) -> io::Result<()> {
567         debug!("Help::write_subcommand");
568         self.none(TAB)?;
569         self.good(sc_str)?;
570         let spec_vals = self.sc_val(sc_str, app)?;
571         self.sc_help(app, &*spec_vals)?;
572         Ok(())
573     }
574 
sc_val(&mut self, sc_str: &str, app: &App) -> Result<String, io::Error>575     fn sc_val(&mut self, sc_str: &str, app: &App) -> Result<String, io::Error> {
576         debug!("Help::sc_val: app={}", app.name);
577         let spec_vals = self.sc_spec_vals(app);
578         let h = app.about.unwrap_or("");
579         let h_w = str_width(h) + str_width(&*spec_vals);
580         let nlh = self.next_line_help;
581         let taken = self.longest + 12;
582         self.force_next_line = !nlh
583             && self.term_w >= taken
584             && (taken as f32 / self.term_w as f32) > 0.40
585             && h_w > (self.term_w - taken);
586 
587         if !(nlh || self.force_next_line) {
588             write_nspaces!(self, self.longest + 4 - (str_width(sc_str)));
589         }
590         Ok(spec_vals)
591     }
592 
sc_spec_vals(&self, a: &App) -> String593     fn sc_spec_vals(&self, a: &App) -> String {
594         debug!("Help::sc_spec_vals: a={}", a.name);
595         let mut spec_vals = vec![];
596         if !a.aliases.is_empty() || !a.short_flag_aliases.is_empty() {
597             debug!("Help::spec_vals: Found aliases...{:?}", a.aliases);
598             debug!(
599                 "Help::spec_vals: Found short flag aliases...{:?}",
600                 a.short_flag_aliases
601             );
602 
603             let mut short_als = a
604                 .get_visible_short_flag_aliases()
605                 .map(|a| format!("-{}", a))
606                 .collect::<Vec<_>>();
607 
608             let als = a.get_visible_aliases().map(|s| s.to_string());
609 
610             short_als.extend(als);
611 
612             let all_als = short_als.join(", ");
613 
614             if !all_als.is_empty() {
615                 spec_vals.push(format!(" [aliases: {}]", all_als));
616             }
617         }
618         spec_vals.join(" ")
619     }
620 
sc_help(&mut self, app: &App<'help>, spec_vals: &str) -> io::Result<()>621     fn sc_help(&mut self, app: &App<'help>, spec_vals: &str) -> io::Result<()> {
622         debug!("Help::sc_help");
623         let h = if self.use_long {
624             app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
625         } else {
626             app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
627         };
628         let mut help = String::from(h) + spec_vals;
629         let nlh = self.next_line_help || self.use_long;
630         debug!("Help::sc_help: Next Line...{:?}", nlh);
631 
632         let spcs = if nlh || self.force_next_line {
633             12 // "tab" * 3
634         } else {
635             self.longest + 12
636         };
637 
638         let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
639 
640         // Is help on next line, if so then indent
641         if nlh || self.force_next_line {
642             self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
643         }
644 
645         debug!("Help::sc_help: Too long...");
646         if too_long && spcs <= self.term_w {
647             debug!("Yes");
648             debug!("Help::sc_help: help...{}", help);
649             debug!("Help::sc_help: help width...{}", str_width(&*help));
650             // Determine how many newlines we need to insert
651             let avail_chars = self.term_w - spcs;
652             debug!("Help::sc_help: Usable space...{}", avail_chars);
653             help = wrap_help(&help, avail_chars);
654         } else {
655             debug!("No");
656         }
657         if let Some(part) = help.lines().next() {
658             self.none(part)?;
659         }
660         for part in help.lines().skip(1) {
661             self.none("\n")?;
662             if nlh || self.force_next_line {
663                 self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
664             } else {
665                 write_nspaces!(self, self.longest + 8);
666             }
667             self.none(part)?;
668         }
669         if !help.contains('\n') && (nlh || self.force_next_line) {
670             self.none("\n")?;
671         }
672         Ok(())
673     }
674 }
675 
676 // Methods to write Parser help.
677 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
678     /// Writes help for all arguments (options, flags, args, subcommands)
679     /// including titles of a Parser Object to the wrapped stream.
write_all_args(&mut self) -> io::Result<()>680     pub(crate) fn write_all_args(&mut self) -> io::Result<()> {
681         debug!("Help::write_all_args");
682         let flags = self.parser.has_flags();
683         let pos = self
684             .parser
685             .app
686             .get_positionals()
687             .filter(|arg| should_show_arg(self.use_long, arg))
688             .any(|_| true);
689         let opts = self
690             .parser
691             .app
692             .get_opts_with_no_heading()
693             .filter(|arg| should_show_arg(self.use_long, arg))
694             .collect::<Vec<_>>();
695         let subcmds = self.parser.has_visible_subcommands();
696 
697         let custom_headings = self
698             .parser
699             .app
700             .args
701             .args
702             .iter()
703             .filter_map(|arg| arg.help_heading)
704             .collect::<IndexSet<_>>();
705 
706         let mut first = if pos {
707             self.warning("ARGS:\n")?;
708             self.write_args_unsorted(&self.parser.app.get_positionals().collect::<Vec<_>>())?;
709             false
710         } else {
711             true
712         };
713 
714         let unified_help = self.parser.is_set(AppSettings::UnifiedHelpMessage);
715 
716         if unified_help && (flags || !opts.is_empty()) {
717             let opts_flags = self
718                 .parser
719                 .app
720                 .args
721                 .args
722                 .iter()
723                 .filter(|a| a.has_switch())
724                 .collect::<Vec<_>>();
725             if !first {
726                 self.none("\n\n")?;
727             }
728             self.warning("OPTIONS:\n")?;
729             self.write_args(&*opts_flags)?;
730             first = false;
731         } else {
732             if flags {
733                 if !first {
734                     self.none("\n\n")?;
735                 }
736                 self.warning("FLAGS:\n")?;
737                 let flags_v: Vec<_> = self.parser.app.get_flags_with_no_heading().collect();
738                 self.write_args(&flags_v)?;
739                 first = false;
740             }
741             if !opts.is_empty() {
742                 if !first {
743                     self.none("\n\n")?;
744                 }
745                 self.warning("OPTIONS:\n")?;
746                 self.write_args(&opts)?;
747                 first = false;
748             }
749             if !custom_headings.is_empty() {
750                 for heading in custom_headings {
751                     if !first {
752                         self.none("\n\n")?;
753                     }
754                     self.warning(&*format!("{}:\n", heading))?;
755                     let args = self
756                         .parser
757                         .app
758                         .args
759                         .args
760                         .iter()
761                         .filter(|a| {
762                             if let Some(help_heading) = a.help_heading {
763                                 return help_heading == heading;
764                             }
765                             false
766                         })
767                         .collect::<Vec<_>>();
768                     self.write_args(&*args)?;
769                     first = false
770                 }
771             }
772         }
773 
774         if subcmds {
775             if !first {
776                 self.none("\n\n")?;
777             }
778 
779             self.warning(self.parser.app.subcommand_header.unwrap_or("SUBCOMMANDS"))?;
780             self.warning(":\n")?;
781 
782             self.write_subcommands(&self.parser.app)?;
783         }
784 
785         Ok(())
786     }
787 
788     /// Writes help for subcommands of a Parser Object to the wrapped stream.
write_subcommands(&mut self, app: &App<'help>) -> io::Result<()>789     fn write_subcommands(&mut self, app: &App<'help>) -> io::Result<()> {
790         debug!("Help::write_subcommands");
791         // The shortest an arg can legally be is 2 (i.e. '-x')
792         self.longest = 2;
793         let mut ord_m = VecMap::new();
794         for sc in app
795             .subcommands
796             .iter()
797             .filter(|s| !s.is_set(AppSettings::Hidden))
798         {
799             let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new());
800             let mut sc_str = String::new();
801             sc_str.push_str(&sc.short_flag.map_or(String::new(), |c| format!("-{}, ", c)));
802             sc_str.push_str(&sc.long_flag.map_or(String::new(), |c| format!("--{}, ", c)));
803             sc_str.push_str(&sc.name);
804             self.longest = cmp::max(self.longest, str_width(&sc_str));
805             btm.insert(sc_str, sc.clone());
806         }
807 
808         debug!("Help::write_subcommands longest = {}", self.longest);
809 
810         let mut first = true;
811         for btm in ord_m.values() {
812             for (sc_str, sc) in btm {
813                 if first {
814                     first = false;
815                 } else {
816                     self.none("\n")?;
817                 }
818                 self.write_subcommand(sc_str, sc)?;
819             }
820         }
821         Ok(())
822     }
823 
824     /// Writes binary name of a Parser Object to the wrapped stream.
write_bin_name(&mut self) -> io::Result<()>825     fn write_bin_name(&mut self) -> io::Result<()> {
826         debug!("Help::write_bin_name");
827         let term_w = self.term_w;
828         macro_rules! write_name {
829             () => {{
830                 self.good(&*wrap_help(&self.parser.app.name, term_w))?;
831             }};
832         }
833         if let Some(bn) = self.parser.app.bin_name.as_ref() {
834             if bn.contains(' ') {
835                 // In case we're dealing with subcommands i.e. git mv is translated to git-mv
836                 self.good(&bn.replace(" ", "-"))?
837             } else {
838                 write_name!();
839             }
840         } else {
841             write_name!();
842         }
843         Ok(())
844     }
845 }
846 
847 // Methods to write Parser help using templates.
848 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
849     /// Write help to stream for the parser in the format defined by the template.
850     ///
851     /// For details about the template language see [`App::help_template`].
852     ///
853     /// [`App::help_template`]: ./struct.App.html#method.help_template
write_templated_help(&mut self, template: &str) -> io::Result<()>854     fn write_templated_help(&mut self, template: &str) -> io::Result<()> {
855         debug!("Help::write_templated_help");
856 
857         // The strategy is to copy the template from the reader to wrapped stream
858         // until a tag is found. Depending on its value, the appropriate content is copied
859         // to the wrapped stream.
860         // The copy from template is then resumed, repeating this sequence until reading
861         // the complete template.
862 
863         macro_rules! tags {
864             (
865                 match $part:ident {
866                     $( $tag:expr => $action:stmt )*
867                 }
868             ) => {
869                 match $part {
870                     $(
871                         part if part.starts_with(concat!($tag, "}")) => {
872                             $action
873                             let rest = &part[$tag.len()+1..];
874                             self.none(rest)?;
875                         }
876                     )*
877 
878                     // Unknown tag, write it back.
879                     part => {
880                         self.none("{")?;
881                         self.none(part)?;
882                     }
883                 }
884             };
885         }
886 
887         let mut parts = template.split('{');
888         if let Some(first) = parts.next() {
889             self.none(first)?;
890         }
891 
892         for part in parts {
893             tags! {
894                 match part {
895                     "bin" => {
896                         self.write_bin_name()?;
897                     }
898                     "version" => {
899                         if let Some(s) = self.parser.app.version {
900                             self.none(s)?;
901                         }
902                     }
903                     "author" => {
904                         if let Some(s) = self.parser.app.author {
905                             self.none(&wrap_help(s, self.term_w))?;
906                         }
907                     }
908                     "author-with-newline" => {
909                         if let Some(s) = self.parser.app.author {
910                             self.none(&wrap_help(s, self.term_w))?;
911                             self.none("\n")?;
912                         }
913                     }
914                     "about" => {
915                         let about = if self.use_long {
916                             self.parser.app.long_about.or(self.parser.app.about)
917                         } else {
918                             self.parser.app.about
919                         };
920                         if let Some(output) = about {
921                             self.none(wrap_help(output, self.term_w))?;
922                         }
923                     }
924                     "about-with-newline" => {
925                         let about = if self.use_long {
926                             self.parser.app.long_about.or(self.parser.app.about)
927                         } else {
928                             self.parser.app.about
929                         };
930                         if let Some(output) = about {
931                             self.none(wrap_help(output, self.term_w))?;
932                             self.none("\n")?;
933                         }
934                     }
935                     "usage-heading" => {
936                         self.warning("USAGE:")?;
937                     }
938                     "usage" => {
939                         self.none(Usage::new(self.parser).create_usage_no_title(&[]))?;
940                     }
941                     "all-args" => {
942                         self.write_all_args()?;
943                     }
944                     "unified" => {
945                         let opts_flags = self
946                             .parser
947                             .app
948                             .args
949                             .args
950                             .iter()
951                             .filter(|a| a.has_switch())
952                             .collect::<Vec<_>>();
953                         self.write_args(&opts_flags)?;
954                     }
955                     "flags" => {
956                         self.write_args(&self.parser.app.get_flags_with_no_heading().collect::<Vec<_>>())?;
957                     }
958                     "options" => {
959                         self.write_args(&self.parser.app.get_opts_with_no_heading().collect::<Vec<_>>())?;
960                     }
961                     "positionals" => {
962                         self.write_args(&self.parser.app.get_positionals().collect::<Vec<_>>())?;
963                     }
964                     "subcommands" => {
965                         self.write_subcommands(self.parser.app)?;
966                     }
967                     "after-help" => {
968                         let after_help = if self.use_long {
969                             self.parser
970                                 .app
971                                 .after_long_help
972                                 .or(self.parser.app.after_help)
973                         } else {
974                             self.parser.app.after_help
975                         };
976                         if let Some(output) = after_help {
977                             self.none("\n\n")?;
978                             self.write_before_after_help(output)?;
979                         }
980                     }
981                     "before-help" => {
982                         let before_help = if self.use_long {
983                             self.parser
984                                 .app
985                                 .before_long_help
986                                 .or(self.parser.app.before_help)
987                         } else {
988                             self.parser.app.before_help
989                         };
990                         if let Some(output) = before_help {
991                             self.write_before_after_help(output)?;
992                             self.none("\n\n")?;
993                         }
994                     }
995                 }
996             }
997         }
998 
999         Ok(())
1000     }
1001 }
1002 
should_show_arg(use_long: bool, arg: &Arg) -> bool1003 fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
1004     debug!("should_show_arg: use_long={:?}, arg={}", use_long, arg.name);
1005     if arg.is_set(ArgSettings::Hidden) {
1006         return false;
1007     }
1008     (!arg.is_set(ArgSettings::HiddenLongHelp) && use_long)
1009         || (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long)
1010         || arg.is_set(ArgSettings::NextLineHelp)
1011 }
1012 
wrap_help(help: &str, avail_chars: usize) -> String1013 fn wrap_help(help: &str, avail_chars: usize) -> String {
1014     let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
1015     help.lines()
1016         .map(|line| wrapper.fill(line))
1017         .collect::<Vec<String>>()
1018         .join("\n")
1019 }
1020 
1021 #[cfg(test)]
1022 mod test {
1023     use super::wrap_help;
1024 
1025     #[test]
wrap_help_last_word()1026     fn wrap_help_last_word() {
1027         let help = String::from("foo bar baz");
1028         assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz");
1029     }
1030 }
1031