clap_v3/parse/errors.rs
1// Std
2use std::convert::From;
3use std::error::Error as StdError;
4use std::fmt as std_fmt;
5use std::fmt::Display;
6use std::io::{self, Write};
7use std::process;
8use std::result::Result as StdResult;
9
10// Internal
11use crate::build::{Arg, ArgGroup};
12use crate::output::fmt::{ColorWhen, Colorizer, ColorizerOption};
13use crate::parse::features::suggestions;
14
15/// Short hand for [`Result`] type
16///
17/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
18pub type Result<T> = StdResult<T, Error>;
19
20/// Command line argument parser kind of error
21#[derive(Debug, Copy, Clone, PartialEq)]
22pub enum ErrorKind {
23 /// Occurs when an [`Arg`] has a set of possible values,
24 /// and the user provides a value which isn't in that set.
25 ///
26 /// # Examples
27 ///
28 /// ```rust
29 /// # use clap::{App, Arg, ErrorKind};
30 /// let result = App::new("prog")
31 /// .arg(Arg::with_name("speed")
32 /// .possible_value("fast")
33 /// .possible_value("slow"))
34 /// .try_get_matches_from(vec!["prog", "other"]);
35 /// assert!(result.is_err());
36 /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidValue);
37 /// ```
38 /// [`Arg`]: ./struct.Arg.html
39 InvalidValue,
40
41 /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
42 ///
43 /// # Examples
44 ///
45 /// ```rust
46 /// # use clap::{App, Arg, ErrorKind};
47 /// let result = App::new("prog")
48 /// .arg(Arg::from("--flag 'some flag'"))
49 /// .try_get_matches_from(vec!["prog", "--other"]);
50 /// assert!(result.is_err());
51 /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnknownArgument);
52 /// ```
53 UnknownArgument,
54
55 /// Occurs when the user provides an unrecognized [``] which meets the threshold for
56 /// being similar enough to an existing subcommand.
57 /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
58 /// the more general [`UnknownArgument`] error is returned.
59 ///
60 /// # Examples
61 ///
62 #[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")]
63 #[cfg_attr(feature = "suggestions", doc = " ```")]
64 /// # use clap::{App, Arg, ErrorKind, };
65 /// let result = App::new("prog")
66 /// .subcommand(App::new("config")
67 /// .about("Used for configuration")
68 /// .arg(Arg::with_name("config_file")
69 /// .help("The configuration file to use")
70 /// .index(1)))
71 /// .try_get_matches_from(vec!["prog", "confi"]);
72 /// assert!(result.is_err());
73 /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand);
74 /// ```
75 /// [``]: ./struct..html
76 /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
77 InvalidSubcommand,
78
79 /// Occurs when the user provides an unrecognized [``] which either
80 /// doesn't meet the threshold for being similar enough to an existing subcommand,
81 /// or the 'suggestions' feature is disabled.
82 /// Otherwise the more detailed [`InvalidSubcommand`] error is returned.
83 ///
84 /// This error typically happens when passing additional subcommand names to the `help`
85 /// subcommand. Otherwise, the more general [`UnknownArgument`] error is used.
86 ///
87 /// # Examples
88 ///
89 /// ```rust
90 /// # use clap::{App, Arg, ErrorKind, };
91 /// let result = App::new("prog")
92 /// .subcommand(App::new("config")
93 /// .about("Used for configuration")
94 /// .arg(Arg::with_name("config_file")
95 /// .help("The configuration file to use")
96 /// .index(1)))
97 /// .try_get_matches_from(vec!["prog", "help", "nothing"]);
98 /// assert!(result.is_err());
99 /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
100 /// ```
101 /// [``]: ./struct..html
102 /// [`InvalidSubcommand`]: ./enum.ErrorKind.html#variant.InvalidSubcommand
103 /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
104 UnrecognizedSubcommand,
105
106 /// Occurs when the user provides an empty value for an option that does not allow empty
107 /// values.
108 ///
109 /// # Examples
110 ///
111 /// ```rust
112 /// # use clap::{App, Arg, ErrorKind, ArgSettings};
113 /// let res = App::new("prog")
114 /// .arg(Arg::with_name("color")
115 /// .setting(ArgSettings::TakesValue)
116 /// .long("color"))
117 /// .try_get_matches_from(vec!["prog", "--color="]);
118 /// assert!(res.is_err());
119 /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
120 /// ```
121 EmptyValue,
122
123 /// Occurs when the user provides a value for an argument with a custom validation and the
124 /// value fails that validation.
125 ///
126 /// # Examples
127 ///
128 /// ```rust
129 /// # use clap::{App, Arg, ErrorKind};
130 /// fn is_numeric(val: String) -> Result<(), String> {
131 /// match val.parse::<i64>() {
132 /// Ok(..) => Ok(()),
133 /// Err(..) => Err(String::from("Value wasn't a number!")),
134 /// }
135 /// }
136 ///
137 /// let result = App::new("prog")
138 /// .arg(Arg::with_name("num")
139 /// .validator(is_numeric))
140 /// .try_get_matches_from(vec!["prog", "NotANumber"]);
141 /// assert!(result.is_err());
142 /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation);
143 /// ```
144 ValueValidation,
145
146 /// Occurs when a user provides more values for an argument than were defined by setting
147 /// [`Arg::max_values`].
148 ///
149 /// # Examples
150 ///
151 /// ```rust
152 /// # use clap::{App, Arg, ErrorKind};
153 /// let result = App::new("prog")
154 /// .arg(Arg::with_name("arg")
155 /// .multiple(true)
156 /// .max_values(2))
157 /// .try_get_matches_from(vec!["prog", "too", "many", "values"]);
158 /// assert!(result.is_err());
159 /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues);
160 /// ```
161 /// [`Arg::max_values`]: ./struct.Arg.html#method.max_values
162 TooManyValues,
163
164 /// Occurs when the user provides fewer values for an argument than were defined by setting
165 /// [`Arg::min_values`].
166 ///
167 /// # Examples
168 ///
169 /// ```rust
170 /// # use clap::{App, Arg, ErrorKind};
171 /// let result = App::new("prog")
172 /// .arg(Arg::with_name("some_opt")
173 /// .long("opt")
174 /// .min_values(3))
175 /// .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
176 /// assert!(result.is_err());
177 /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues);
178 /// ```
179 /// [`Arg::min_values`]: ./struct.Arg.html#method.min_values
180 TooFewValues,
181
182 /// Occurs when the user provides a different number of values for an argument than what's
183 /// been defined by setting [`Arg::number_of_values`] or than was implicitly set by
184 /// [`Arg::value_names`].
185 ///
186 /// # Examples
187 ///
188 /// ```rust
189 /// # use clap::{App, Arg, ErrorKind};
190 /// let result = App::new("prog")
191 /// .arg(Arg::with_name("some_opt")
192 /// .long("opt")
193 /// .takes_value(true)
194 /// .number_of_values(2))
195 /// .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
196 /// assert!(result.is_err());
197 /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
198 /// ```
199 ///
200 /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values
201 /// [`Arg::value_names`]: ./struct.Arg.html#method.value_names
202 WrongNumberOfValues,
203
204 /// Occurs when the user provides two values which conflict with each other and can't be used
205 /// together.
206 ///
207 /// # Examples
208 ///
209 /// ```rust
210 /// # use clap::{App, Arg, ErrorKind};
211 /// let result = App::new("prog")
212 /// .arg(Arg::with_name("debug")
213 /// .long("debug")
214 /// .conflicts_with("color"))
215 /// .arg(Arg::with_name("color")
216 /// .long("color"))
217 /// .try_get_matches_from(vec!["prog", "--debug", "--color"]);
218 /// assert!(result.is_err());
219 /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict);
220 /// ```
221 ArgumentConflict,
222
223 /// Occurs when the user does not provide one or more required arguments.
224 ///
225 /// # Examples
226 ///
227 /// ```rust
228 /// # use clap::{App, Arg, ErrorKind};
229 /// let result = App::new("prog")
230 /// .arg(Arg::with_name("debug")
231 /// .required(true))
232 /// .try_get_matches_from(vec!["prog"]);
233 /// assert!(result.is_err());
234 /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
235 /// ```
236 MissingRequiredArgument,
237
238 /// Occurs when a subcommand is required (as defined by [`AppSettings::SubcommandRequired`]),
239 /// but the user does not provide one.
240 ///
241 /// # Examples
242 ///
243 /// ```rust
244 /// # use clap::{App, AppSettings, ErrorKind};
245 /// let err = App::new("prog")
246 /// .setting(AppSettings::SubcommandRequired)
247 /// .subcommand(App::new("test"))
248 /// .try_get_matches_from(vec![
249 /// "myprog",
250 /// ]);
251 /// assert!(err.is_err());
252 /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand);
253 /// # ;
254 /// ```
255 /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired
256 MissingSubcommand,
257
258 /// Occurs when either an argument or [``] is required, as defined by
259 /// [`AppSettings::ArgRequiredElseHelp`], but the user did not provide one.
260 ///
261 /// # Examples
262 ///
263 /// ```rust
264 /// # use clap::{App, Arg, AppSettings, ErrorKind, };
265 /// let result = App::new("prog")
266 /// .setting(AppSettings::ArgRequiredElseHelp)
267 /// .subcommand(App::new("config")
268 /// .about("Used for configuration")
269 /// .arg(Arg::with_name("config_file")
270 /// .help("The configuration file to use")))
271 /// .try_get_matches_from(vec!["prog"]);
272 /// assert!(result.is_err());
273 /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingArgumentOrSubcommand);
274 /// ```
275 /// [``]: ./struct..html
276 /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp
277 MissingArgumentOrSubcommand,
278
279 /// Occurs when the user provides multiple values to an argument which doesn't allow that.
280 ///
281 /// # Examples
282 ///
283 /// ```rust
284 /// # use clap::{App, Arg, ErrorKind};
285 /// let result = App::new("prog")
286 /// .arg(Arg::with_name("debug")
287 /// .long("debug")
288 /// .multiple(false))
289 /// .try_get_matches_from(vec!["prog", "--debug", "--debug"]);
290 /// assert!(result.is_err());
291 /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage);
292 /// ```
293 UnexpectedMultipleUsage,
294
295 /// Occurs when the user provides a value containing invalid UTF-8 for an argument and
296 /// [`AppSettings::StrictUtf8`] is set.
297 ///
298 /// # Platform Specific
299 ///
300 /// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
301 ///
302 /// # Examples
303 ///
304 #[cfg_attr(not(unix), doc = " ```ignore")]
305 #[cfg_attr(unix, doc = " ```")]
306 /// # use clap::{App, Arg, ErrorKind, AppSettings};
307 /// # use std::os::unix::ffi::OsStringExt;
308 /// # use std::ffi::OsString;
309 /// let result = App::new("prog")
310 /// .setting(AppSettings::StrictUtf8)
311 /// .arg(Arg::with_name("utf8")
312 /// .short('u')
313 /// .takes_value(true))
314 /// .try_get_matches_from(vec![OsString::from("myprog"),
315 /// OsString::from("-u"),
316 /// OsString::from_vec(vec![0xE9])]);
317 /// assert!(result.is_err());
318 /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidUtf8);
319 /// ```
320 /// [`AppSettings::StrictUtf8`]: ./enum.AppSettings.html#variant.StrictUtf8
321 InvalidUtf8,
322
323 /// Not a true "error" as it means `--help` or similar was used.
324 /// The help message will be sent to `stdout`.
325 ///
326 /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
327 /// be sent to `stderr` instead of `stdout`.
328 ///
329 /// # Examples
330 ///
331 /// ```rust
332 /// # use clap::{App, Arg, ErrorKind};
333 /// let result = App::new("prog")
334 /// .try_get_matches_from(vec!["prog", "--help"]);
335 /// assert!(result.is_err());
336 /// assert_eq!(result.unwrap_err().kind, ErrorKind::HelpDisplayed);
337 /// ```
338 HelpDisplayed,
339
340 /// Not a true "error" as it means `--version` or similar was used.
341 /// The message will be sent to `stdout`.
342 ///
343 /// # Examples
344 ///
345 /// ```rust
346 /// # use clap::{App, Arg, ErrorKind};
347 /// let result = App::new("prog")
348 /// .try_get_matches_from(vec!["prog", "--version"]);
349 /// assert!(result.is_err());
350 /// assert_eq!(result.unwrap_err().kind, ErrorKind::VersionDisplayed);
351 /// ```
352 VersionDisplayed,
353
354 /// Occurs when using the [`value_t!`] and [`values_t!`] macros to convert an argument value
355 /// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument
356 /// with name `config` to be converted, but `config` wasn't used by the user.
357 /// [`value_t!`]: ./macro.value_t!.html
358 /// [`values_t!`]: ./macro.values_t!.html
359 ArgumentNotFound,
360
361 /// Represents an [I/O error].
362 /// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
363 /// [I/O error]: https://doc.rust-lang.org/std/io/struct.Error.html
364 Io,
365
366 /// Represents a [Format error] (which is a part of [`Display`]).
367 /// Typically caused by writing to `stderr` or `stdout`.
368 ///
369 /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
370 /// [Format error]: https://doc.rust-lang.org/std/fmt/struct.Error.html
371 Format,
372}
373
374/// Command Line Argument Parser Error
375#[derive(Debug)]
376pub struct Error {
377 /// The cause of the error
378 pub cause: String,
379 /// Formatted error message, enhancing the cause message with extra information
380 pub message: String,
381 /// The type of error
382 pub kind: ErrorKind,
383 /// Any additional information passed along, such as the argument name that caused the error
384 pub info: Option<Vec<String>>,
385}
386
387impl Error {
388 /// Returns the singular or plural form on the verb to be based on the argument's value.
389 fn singular_or_plural(n: usize) -> String {
390 if n > 1 {
391 String::from("were")
392 } else {
393 String::from("was")
394 }
395 }
396
397 /// Should the message be written to `stdout` or not
398 pub fn use_stderr(&self) -> bool {
399 match self.kind {
400 ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed => false,
401 _ => true,
402 }
403 }
404
405 /// Prints the error to `stderr` and exits with a status of `1`
406 pub fn exit(&self) -> ! {
407 if self.use_stderr() {
408 wlnerr!("{}", self.message);
409 process::exit(1);
410 }
411 let out = io::stdout();
412 writeln!(&mut out.lock(), "{}", self.message).expect("Error writing Error to stdout");
413 process::exit(0);
414 }
415
416 #[doc(hidden)]
417 pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> {
418 write!(w, "{}", self.message)
419 }
420
421 #[doc(hidden)]
422 pub fn group_conflict<O, U>(
423 group: &ArgGroup,
424 other: Option<O>,
425 usage: U,
426 color: ColorWhen,
427 ) -> Self
428 where
429 O: Into<String>,
430 U: Display,
431 {
432 let mut v = vec![group.name.to_owned()];
433 let c = Colorizer::new(&ColorizerOption {
434 use_stderr: true,
435 when: color,
436 });
437 let (plain_cause, colored_cause) = match other {
438 Some(name) => {
439 let n = name.into();
440 v.push(n.clone());
441 (
442 format!("The argument '{}' cannot be used with '{}'", group.name, n),
443 format!(
444 "The argument '{}' cannot be used with '{}'",
445 group.name,
446 c.warning(n)
447 ),
448 )
449 }
450 None => {
451 let n = "one or more of the other specified arguments";
452 (
453 format!("The argument '{}' cannot be used with {}", group.name, n),
454 format!(
455 "The argument '{}' cannot be used with {}",
456 group.name,
457 c.none(n)
458 ),
459 )
460 }
461 };
462 Error {
463 cause: plain_cause,
464 message: format!(
465 "{} {}\n\n{}\n\nFor more information try {}",
466 c.error("error:"),
467 colored_cause,
468 usage,
469 c.good("--help")
470 ),
471 kind: ErrorKind::ArgumentConflict,
472 info: Some(v),
473 }
474 }
475
476 #[doc(hidden)]
477 pub fn argument_conflict<O, U>(arg: &Arg, other: Option<O>, usage: U, color: ColorWhen) -> Self
478 where
479 O: Into<String>,
480 U: Display,
481 {
482 let mut v = vec![arg.name.to_owned()];
483 let c = Colorizer::new(&ColorizerOption {
484 use_stderr: true,
485 when: color,
486 });
487 let (plain_cause, colored_cause) = match other {
488 Some(name) => {
489 let n = name.into();
490 v.push(n.clone());
491 (
492 format!("The argument '{}' cannot be used with '{}'", arg, n),
493 format!(
494 "The argument '{}' cannot be used with {}",
495 c.warning(arg.to_string()),
496 c.warning(format!("'{}'", n))
497 ),
498 )
499 }
500 None => {
501 let n = "one or more of the other specified arguments";
502 (
503 format!("The argument '{}' cannot be used with {}", arg, n),
504 format!(
505 "The argument '{}' cannot be used with {}",
506 c.warning(arg.to_string()),
507 c.none(n)
508 ),
509 )
510 }
511 };
512 Error {
513 cause: plain_cause,
514 message: format!(
515 "{} {}\n\n{}\n\nFor more information try {}",
516 c.error("error:"),
517 colored_cause,
518 usage,
519 c.good("--help")
520 ),
521 kind: ErrorKind::ArgumentConflict,
522 info: Some(v),
523 }
524 }
525
526 #[doc(hidden)]
527 pub fn empty_value<U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
528 where
529 U: Display,
530 {
531 let c = Colorizer::new(&ColorizerOption {
532 use_stderr: true,
533 when: color,
534 });
535 Error {
536 cause: format!(
537 "The argument '{}' requires a value but none was supplied",
538 arg
539 ),
540 message: format!(
541 "{} The argument '{}' requires a value but none was supplied\
542 \n\n\
543 {}\n\n\
544 For more information try {}",
545 c.error("error:"),
546 c.warning(arg.to_string()),
547 usage,
548 c.good("--help")
549 ),
550 kind: ErrorKind::EmptyValue,
551 info: Some(vec![arg.name.to_owned()]),
552 }
553 }
554
555 #[doc(hidden)]
556 pub fn invalid_value<B, G, U>(
557 bad_val: B,
558 good_vals: &[G],
559 arg: &Arg,
560 usage: U,
561 color: ColorWhen,
562 ) -> Self
563 where
564 B: AsRef<str>,
565 G: AsRef<str> + Display,
566 U: Display,
567 {
568 let c = Colorizer::new(&ColorizerOption {
569 use_stderr: true,
570 when: color,
571 });
572 let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter());
573
574 let mut sorted = vec![];
575 for v in good_vals {
576 let val = format!("{}", c.good(v));
577 sorted.push(val);
578 }
579 sorted.sort();
580 let valid_values = sorted.join(", ");
581 Error {
582 cause: format!(
583 "'{}' isn't a valid value for '{}'\n\t\
584 [possible values: {}]",
585 bad_val.as_ref(),
586 arg,
587 valid_values
588 ),
589 message: format!(
590 "{} '{}' isn't a valid value for '{}'\n\t\
591 [possible values: {}]\n\
592 {}\n\n\
593 {}\n\n\
594 For more information try {}",
595 c.error("error:"),
596 c.warning(bad_val.as_ref()),
597 c.warning(arg.to_string()),
598 valid_values,
599 suffix.0,
600 usage,
601 c.good("--help")
602 ),
603 kind: ErrorKind::InvalidValue,
604 info: Some(vec![arg.name.to_owned(), bad_val.as_ref().to_owned()]),
605 }
606 }
607
608 #[doc(hidden)]
609 pub fn invalid_subcommand<S, D, N, U>(
610 subcmd: S,
611 did_you_mean: D,
612 name: N,
613 usage: U,
614 color: ColorWhen,
615 ) -> Self
616 where
617 S: Into<String>,
618 D: AsRef<str> + Display,
619 N: Display,
620 U: Display,
621 {
622 let s = subcmd.into();
623 let c = Colorizer::new(&ColorizerOption {
624 use_stderr: true,
625 when: color,
626 });
627 Error {
628 cause: format!("The subcommand '{}' wasn't recognized", s),
629 message: format!(
630 "{} The subcommand '{}' wasn't recognized\n\t\
631 Did you mean {}?\n\n\
632 If you believe you received this message in error, try \
633 re-running with '{} {} {}'\n\n\
634 {}\n\n\
635 For more information try {}",
636 c.error("error:"),
637 c.warning(&*s),
638 c.good(did_you_mean.as_ref()),
639 name,
640 c.good("--"),
641 &*s,
642 usage,
643 c.good("--help")
644 ),
645 kind: ErrorKind::InvalidSubcommand,
646 info: Some(vec![s]),
647 }
648 }
649
650 #[doc(hidden)]
651 pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: ColorWhen) -> Self
652 where
653 S: Into<String>,
654 N: Display,
655 {
656 let s = subcmd.into();
657 let c = Colorizer::new(&ColorizerOption {
658 use_stderr: true,
659 when: color,
660 });
661 Error {
662 cause: format!("The subcommand '{}' wasn't recognized", s),
663 message: format!(
664 "{} The subcommand '{}' wasn't recognized\n\n\
665 {}\n\t\
666 {} help <subcommands>...\n\n\
667 For more information try {}",
668 c.error("error:"),
669 c.warning(&*s),
670 c.warning("USAGE:"),
671 name,
672 c.good("--help")
673 ),
674 kind: ErrorKind::UnrecognizedSubcommand,
675 info: Some(vec![s]),
676 }
677 }
678
679 #[doc(hidden)]
680 pub fn missing_required_argument<R, U>(required: R, usage: U, color: ColorWhen) -> Self
681 where
682 R: Display,
683 U: Display,
684 {
685 let c = Colorizer::new(&ColorizerOption {
686 use_stderr: true,
687 when: color,
688 });
689 Error {
690 cause: format!(
691 "The following required arguments were not provided:{}",
692 required
693 ),
694 message: format!(
695 "{} The following required arguments were not provided:{}\n\n\
696 {}\n\n\
697 For more information try {}",
698 c.error("error:"),
699 required,
700 usage,
701 c.good("--help")
702 ),
703 kind: ErrorKind::MissingRequiredArgument,
704 info: None,
705 }
706 }
707
708 #[doc(hidden)]
709 pub fn missing_subcommand<N, U>(name: N, usage: U, color: ColorWhen) -> Self
710 where
711 N: AsRef<str> + Display,
712 U: Display,
713 {
714 let c = Colorizer::new(&ColorizerOption {
715 use_stderr: true,
716 when: color,
717 });
718 Error {
719 cause: format!("'{}' requires a subcommand, but one was not provided", name),
720 message: format!(
721 "{} '{}' requires a subcommand, but one was not provided\n\n\
722 {}\n\n\
723 For more information try {}",
724 c.error("error:"),
725 c.warning(name),
726 usage,
727 c.good("--help")
728 ),
729 kind: ErrorKind::MissingSubcommand,
730 info: None,
731 }
732 }
733
734 #[doc(hidden)]
735 pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
736 where
737 U: Display,
738 {
739 let c = Colorizer::new(&ColorizerOption {
740 use_stderr: true,
741 when: color,
742 });
743 Error {
744 cause: "Invalid UTF-8 was detected in one or more arguments".to_string(),
745 message: format!(
746 "{} Invalid UTF-8 was detected in one or more arguments\n\n\
747 {}\n\n\
748 For more information try {}",
749 c.error("error:"),
750 usage,
751 c.good("--help")
752 ),
753 kind: ErrorKind::InvalidUtf8,
754 info: None,
755 }
756 }
757
758 #[doc(hidden)]
759 pub fn too_many_values<V, U>(val: V, arg: &Arg, usage: U, color: ColorWhen) -> Self
760 where
761 V: AsRef<str> + Display + ToOwned,
762 U: Display,
763 {
764 let v = val.as_ref();
765 let c = Colorizer::new(&ColorizerOption {
766 use_stderr: true,
767 when: color,
768 });
769 Error {
770 cause: format!(
771 "The value '{}' was provided to '{}', but it wasn't expecting any more values",
772 v, arg
773 ),
774 message: format!(
775 "{} The value '{}' was provided to '{}', but it wasn't expecting \
776 any more values\n\n\
777 {}\n\n\
778 For more information try {}",
779 c.error("error:"),
780 c.warning(v),
781 c.warning(arg.to_string()),
782 usage,
783 c.good("--help")
784 ),
785 kind: ErrorKind::TooManyValues,
786 info: Some(vec![arg.name.to_owned(), v.to_owned()]),
787 }
788 }
789
790 #[doc(hidden)]
791 pub fn too_few_values<U>(
792 arg: &Arg,
793 min_vals: u64,
794 curr_vals: usize,
795 usage: U,
796 color: ColorWhen,
797 ) -> Self
798 where
799 U: Display,
800 {
801 let c = Colorizer::new(&ColorizerOption {
802 use_stderr: true,
803 when: color,
804 });
805 let verb = Error::singular_or_plural(curr_vals);
806 Error {
807 cause: format!(
808 "The argument '{}' requires at least {} values, but only {} {} provided",
809 arg, min_vals, curr_vals, verb
810 ),
811 message: format!(
812 "{} The argument '{}' requires at least {} values, but only {} {} \
813 provided\n\n\
814 {}\n\n\
815 For more information try {}",
816 c.error("error:"),
817 c.warning(arg.to_string()),
818 c.warning(min_vals.to_string()),
819 c.warning(curr_vals.to_string()),
820 verb,
821 usage,
822 c.good("--help")
823 ),
824 kind: ErrorKind::TooFewValues,
825 info: Some(vec![arg.name.to_owned()]),
826 }
827 }
828
829 #[doc(hidden)]
830 pub fn value_validation(arg: Option<&Arg>, err: &str, color: ColorWhen) -> Self {
831 let c = Colorizer::new(&ColorizerOption {
832 use_stderr: true,
833 when: color,
834 });
835 Error {
836 cause: format!(
837 "Invalid value{}: {}",
838 if let Some(a) = arg {
839 format!(" for '{}'", a)
840 } else {
841 String::new()
842 },
843 err
844 ),
845 message: format!(
846 "{} Invalid value{}: {}",
847 c.error("error:"),
848 if let Some(a) = arg {
849 format!(" for '{}'", c.warning(a.to_string()))
850 } else {
851 "".to_string()
852 },
853 err
854 ),
855 kind: ErrorKind::ValueValidation,
856 info: None,
857 }
858 }
859
860 #[doc(hidden)]
861 pub fn value_validation_auto(err: &str) -> Self {
862 let n: Option<&Arg> = None;
863 Error::value_validation(n, err, ColorWhen::Auto)
864 }
865
866 #[doc(hidden)]
867 pub fn wrong_number_of_values<U>(
868 arg: &Arg,
869 num_vals: u64,
870 curr_vals: usize,
871 usage: U,
872 color: ColorWhen,
873 ) -> Self
874 where
875 U: Display,
876 {
877 let c = Colorizer::new(&ColorizerOption {
878 use_stderr: true,
879 when: color,
880 });
881 let verb = Error::singular_or_plural(curr_vals);
882 Error {
883 cause: format!(
884 "The argument '{}' requires {} values, but {} {} provided",
885 arg, num_vals, curr_vals, verb
886 ),
887 message: format!(
888 "{} The argument '{}' requires {} values, but {} {}
889 provided\n\n\
890 {}\n\n\
891 For more information try {}",
892 c.error("error:"),
893 c.warning(arg.to_string()),
894 c.warning(num_vals.to_string()),
895 c.warning(curr_vals.to_string()),
896 verb,
897 usage,
898 c.good("--help")
899 ),
900 kind: ErrorKind::WrongNumberOfValues,
901 info: Some(vec![arg.name.to_owned()]),
902 }
903 }
904
905 #[doc(hidden)]
906 pub fn unexpected_multiple_usage<U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
907 where
908 U: Display,
909 {
910 let c = Colorizer::new(&ColorizerOption {
911 use_stderr: true,
912 when: color,
913 });
914 Error {
915 cause: format!(
916 "The argument '{}' was provided more than once, but cannot be used multiple times",
917 arg
918 ),
919 message: format!(
920 "{} The argument '{}' was provided more than once, but cannot \
921 be used multiple times\n\n\
922 {}\n\n\
923 For more information try {}",
924 c.error("error:"),
925 c.warning(arg.to_string()),
926 usage,
927 c.good("--help")
928 ),
929 kind: ErrorKind::UnexpectedMultipleUsage,
930 info: Some(vec![arg.name.to_owned()]),
931 }
932 }
933
934 #[doc(hidden)]
935 pub fn unknown_argument<A, U>(
936 arg: A,
937 did_you_mean: Option<String>,
938 usage: U,
939 color: ColorWhen,
940 ) -> Self
941 where
942 A: Into<String>,
943 U: Display,
944 {
945 let a = arg.into();
946 let c = Colorizer::new(&ColorizerOption {
947 use_stderr: true,
948 when: color,
949 });
950
951 let suggest_pattern = format!("If you tried to supply `{}` as a PATTERN use `-- {}`", a, a);
952
953 let did_you_mean_message = match did_you_mean {
954 Some(s) => format!("{}\n", s),
955 _ => "\n".to_owned(),
956 };
957
958 Error {
959 cause: format!(
960 "Found argument '{}' which wasn't expected, or isn't valid in this context{}",
961 a, did_you_mean_message
962 ),
963 message: format!(
964 "{} Found argument '{}' which wasn't expected, or isn't valid in \
965 this context{}\
966 {}\n\n\
967 {}\n\n\
968 For more information try {}",
969 c.error("error:"),
970 c.warning(&*a),
971 did_you_mean_message,
972 suggest_pattern,
973 usage,
974 c.good("--help")
975 ),
976 kind: ErrorKind::UnknownArgument,
977 info: Some(vec![a]),
978 }
979 }
980
981 #[doc(hidden)]
982 pub fn io_error(e: &Error, color: ColorWhen) -> Self {
983 let c = Colorizer::new(&ColorizerOption {
984 use_stderr: true,
985 when: color,
986 });
987 Error {
988 cause: e.to_string(),
989 message: format!("{} {}", c.error("error:"), e),
990 kind: ErrorKind::Io,
991 info: None,
992 }
993 }
994
995 #[doc(hidden)]
996 pub fn argument_not_found_auto<A>(arg: A) -> Self
997 where
998 A: Into<String>,
999 {
1000 let a = arg.into();
1001 let c = Colorizer::new(&ColorizerOption {
1002 use_stderr: true,
1003 when: ColorWhen::Auto,
1004 });
1005 Error {
1006 cause: format!("The argument '{}' wasn't found", a),
1007 message: format!("{} The argument '{}' wasn't found", c.error("error:"), a),
1008 kind: ErrorKind::ArgumentNotFound,
1009 info: Some(vec![a]),
1010 }
1011 }
1012
1013 /// Create an error with a custom description.
1014 ///
1015 /// This can be used in combination with `Error::exit` to exit your program
1016 /// with a custom error message.
1017 pub fn with_description(description: impl Into<String>, kind: ErrorKind) -> Self {
1018 let c = Colorizer::new(&ColorizerOption {
1019 use_stderr: true,
1020 when: ColorWhen::Auto,
1021 });
1022
1023 let cause = description.into();
1024 let message = format!("{} {}", c.error("error:"), cause);
1025
1026 Error {
1027 cause,
1028 message,
1029 kind,
1030 info: None,
1031 }
1032 }
1033}
1034
1035impl StdError for Error {}
1036
1037impl Display for Error {
1038 fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result {
1039 writeln!(f, "{}", self.message)
1040 }
1041}
1042
1043impl From<io::Error> for Error {
1044 fn from(e: io::Error) -> Self {
1045 Error::with_description(e.to_string(), ErrorKind::Io)
1046 }
1047}
1048
1049impl From<std_fmt::Error> for Error {
1050 fn from(e: std_fmt::Error) -> Self {
1051 Error::with_description(e.to_string(), ErrorKind::Format)
1052 }
1053}