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