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