clap/
errors.rs

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