clap/
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 args::AnyArg;
12use fmt::{ColorWhen, Colorizer, ColorizerOption};
13use 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    ///     .get_matches_from_safe(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_usage("--flag 'some flag'"))
49    ///     .get_matches_from_safe(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 [`SubCommand`] 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, SubCommand};
65    /// let result = App::new("prog")
66    ///     .subcommand(SubCommand::with_name("config")
67    ///         .about("Used for configuration")
68    ///         .arg(Arg::with_name("config_file")
69    ///             .help("The configuration file to use")
70    ///             .index(1)))
71    ///     .get_matches_from_safe(vec!["prog", "confi"]);
72    /// assert!(result.is_err());
73    /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand);
74    /// ```
75    /// [`SubCommand`]: ./struct.SubCommand.html
76    /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
77    InvalidSubcommand,
78
79    /// Occurs when the user provides an unrecognized [`SubCommand`] 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, SubCommand};
91    /// let result = App::new("prog")
92    ///     .subcommand(SubCommand::with_name("config")
93    ///         .about("Used for configuration")
94    ///         .arg(Arg::with_name("config_file")
95    ///             .help("The configuration file to use")
96    ///             .index(1)))
97    ///     .get_matches_from_safe(vec!["prog", "help", "nothing"]);
98    /// assert!(result.is_err());
99    /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
100    /// ```
101    /// [`SubCommand`]: ./struct.SubCommand.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};
113    /// let res = App::new("prog")
114    ///     .arg(Arg::with_name("color")
115    ///          .long("color")
116    ///          .empty_values(false))
117    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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, SubCommand, ErrorKind};
245    /// let err = App::new("prog")
246    ///     .setting(AppSettings::SubcommandRequired)
247    ///     .subcommand(SubCommand::with_name("test"))
248    ///     .get_matches_from_safe(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 [`SubCommand`] 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, SubCommand};
265    /// let result = App::new("prog")
266    ///     .setting(AppSettings::ArgRequiredElseHelp)
267    ///     .subcommand(SubCommand::with_name("config")
268    ///         .about("Used for configuration")
269    ///         .arg(Arg::with_name("config_file")
270    ///             .help("The configuration file to use")))
271    ///     .get_matches_from_safe(vec!["prog"]);
272    /// assert!(result.is_err());
273    /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingArgumentOrSubcommand);
274    /// ```
275    /// [`SubCommand`]: ./struct.SubCommand.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    ///     .get_matches_from_safe(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, macOS, 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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    ///     .get_matches_from_safe(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    /// Formatted error message
378    pub message: String,
379    /// The type of error
380    pub kind: ErrorKind,
381    /// Any additional information passed along, such as the argument name that caused the error
382    pub info: Option<Vec<String>>,
383}
384
385impl Error {
386    /// Should the message be written to `stdout` or not
387    pub fn use_stderr(&self) -> bool {
388        match self.kind {
389            ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed => false,
390            _ => true,
391        }
392    }
393
394    /// Prints the error to `stderr` and exits with a status of `1`
395    pub fn exit(&self) -> ! {
396        if self.use_stderr() {
397            wlnerr!("{}", self.message);
398            process::exit(1);
399        }
400        let out = io::stdout();
401        writeln!(&mut out.lock(), "{}", self.message).expect("Error writing Error to stdout");
402        process::exit(0);
403    }
404
405    #[doc(hidden)]
406    pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
407
408    #[doc(hidden)]
409    pub fn argument_conflict<O, U>(
410        arg: &AnyArg,
411        other: Option<O>,
412        usage: U,
413        color: ColorWhen,
414    ) -> Self
415    where
416        O: Into<String>,
417        U: Display,
418    {
419        let mut v = vec![arg.name().to_owned()];
420        let c = Colorizer::new(ColorizerOption {
421            use_stderr: true,
422            when: color,
423        });
424        Error {
425            message: format!(
426                "{} The argument '{}' cannot be used with {}\n\n\
427                 {}\n\n\
428                 For more information try {}",
429                c.error("error:"),
430                c.warning(&*arg.to_string()),
431                match other {
432                    Some(name) => {
433                        let n = name.into();
434                        v.push(n.clone());
435                        c.warning(format!("'{}'", n))
436                    }
437                    None => c.none("one or more of the other specified arguments".to_owned()),
438                },
439                usage,
440                c.good("--help")
441            ),
442            kind: ErrorKind::ArgumentConflict,
443            info: Some(v),
444        }
445    }
446
447    #[doc(hidden)]
448    pub fn empty_value<U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
449    where
450        U: Display,
451    {
452        let c = Colorizer::new(ColorizerOption {
453            use_stderr: true,
454            when: color,
455        });
456        Error {
457            message: format!(
458                "{} The argument '{}' requires a value but none was supplied\
459                 \n\n\
460                 {}\n\n\
461                 For more information try {}",
462                c.error("error:"),
463                c.warning(arg.to_string()),
464                usage,
465                c.good("--help")
466            ),
467            kind: ErrorKind::EmptyValue,
468            info: Some(vec![arg.name().to_owned()]),
469        }
470    }
471
472    #[doc(hidden)]
473    pub fn invalid_value<B, G, U>(
474        bad_val: B,
475        good_vals: &[G],
476        arg: &AnyArg,
477        usage: U,
478        color: ColorWhen,
479    ) -> Self
480    where
481        B: AsRef<str>,
482        G: AsRef<str> + Display,
483        U: Display,
484    {
485        let c = Colorizer::new(ColorizerOption {
486            use_stderr: true,
487            when: color,
488        });
489        let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter());
490
491        let mut sorted = vec![];
492        for v in good_vals {
493            let val = format!("{}", c.good(v));
494            sorted.push(val);
495        }
496        sorted.sort();
497        let valid_values = sorted.join(", ");
498        Error {
499            message: format!(
500                "{} '{}' isn't a valid value for '{}'\n\t\
501                 [possible values: {}]\n\
502                 {}\n\n\
503                 {}\n\n\
504                 For more information try {}",
505                c.error("error:"),
506                c.warning(bad_val.as_ref()),
507                c.warning(arg.to_string()),
508                valid_values,
509                suffix.0,
510                usage,
511                c.good("--help")
512            ),
513            kind: ErrorKind::InvalidValue,
514            info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
515        }
516    }
517
518    #[doc(hidden)]
519    pub fn invalid_subcommand<S, D, N, U>(
520        subcmd: S,
521        did_you_mean: D,
522        name: N,
523        usage: U,
524        color: ColorWhen,
525    ) -> Self
526    where
527        S: Into<String>,
528        D: AsRef<str> + Display,
529        N: Display,
530        U: Display,
531    {
532        let s = subcmd.into();
533        let c = Colorizer::new(ColorizerOption {
534            use_stderr: true,
535            when: color,
536        });
537        Error {
538            message: format!(
539                "{} The subcommand '{}' wasn't recognized\n\t\
540                 Did you mean '{}'?\n\n\
541                 If you believe you received this message in error, try \
542                 re-running with '{} {} {}'\n\n\
543                 {}\n\n\
544                 For more information try {}",
545                c.error("error:"),
546                c.warning(&*s),
547                c.good(did_you_mean.as_ref()),
548                name,
549                c.good("--"),
550                &*s,
551                usage,
552                c.good("--help")
553            ),
554            kind: ErrorKind::InvalidSubcommand,
555            info: Some(vec![s]),
556        }
557    }
558
559    #[doc(hidden)]
560    pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: ColorWhen) -> Self
561    where
562        S: Into<String>,
563        N: Display,
564    {
565        let s = subcmd.into();
566        let c = Colorizer::new(ColorizerOption {
567            use_stderr: true,
568            when: color,
569        });
570        Error {
571            message: format!(
572                "{} The subcommand '{}' wasn't recognized\n\n\
573                 {}\n\t\
574                 {} help <subcommands>...\n\n\
575                 For more information try {}",
576                c.error("error:"),
577                c.warning(&*s),
578                c.warning("USAGE:"),
579                name,
580                c.good("--help")
581            ),
582            kind: ErrorKind::UnrecognizedSubcommand,
583            info: Some(vec![s]),
584        }
585    }
586
587    #[doc(hidden)]
588    pub fn missing_required_argument<R, U>(required: R, usage: U, color: ColorWhen) -> Self
589    where
590        R: Display,
591        U: Display,
592    {
593        let c = Colorizer::new(ColorizerOption {
594            use_stderr: true,
595            when: color,
596        });
597        Error {
598            message: format!(
599                "{} The following required arguments were not provided:{}\n\n\
600                 {}\n\n\
601                 For more information try {}",
602                c.error("error:"),
603                required,
604                usage,
605                c.good("--help")
606            ),
607            kind: ErrorKind::MissingRequiredArgument,
608            info: None,
609        }
610    }
611
612    #[doc(hidden)]
613    pub fn missing_subcommand<N, U>(name: N, usage: U, color: ColorWhen) -> Self
614    where
615        N: AsRef<str> + Display,
616        U: Display,
617    {
618        let c = Colorizer::new(ColorizerOption {
619            use_stderr: true,
620            when: color,
621        });
622        Error {
623            message: format!(
624                "{} '{}' requires a subcommand, but one was not provided\n\n\
625                 {}\n\n\
626                 For more information try {}",
627                c.error("error:"),
628                c.warning(name),
629                usage,
630                c.good("--help")
631            ),
632            kind: ErrorKind::MissingSubcommand,
633            info: None,
634        }
635    }
636
637
638    #[doc(hidden)]
639    pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
640    where
641        U: Display,
642    {
643        let c = Colorizer::new(ColorizerOption {
644            use_stderr: true,
645            when: color,
646        });
647        Error {
648            message: format!(
649                "{} Invalid UTF-8 was detected in one or more arguments\n\n\
650                 {}\n\n\
651                 For more information try {}",
652                c.error("error:"),
653                usage,
654                c.good("--help")
655            ),
656            kind: ErrorKind::InvalidUtf8,
657            info: None,
658        }
659    }
660
661    #[doc(hidden)]
662    pub fn too_many_values<V, U>(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self
663    where
664        V: AsRef<str> + Display + ToOwned,
665        U: Display,
666    {
667        let v = val.as_ref();
668        let c = Colorizer::new(ColorizerOption {
669            use_stderr: true,
670            when: color,
671        });
672        Error {
673            message: format!(
674                "{} The value '{}' was provided to '{}', but it wasn't expecting \
675                 any more values\n\n\
676                 {}\n\n\
677                 For more information try {}",
678                c.error("error:"),
679                c.warning(v),
680                c.warning(arg.to_string()),
681                usage,
682                c.good("--help")
683            ),
684            kind: ErrorKind::TooManyValues,
685            info: Some(vec![arg.name().to_owned(), v.to_owned()]),
686        }
687    }
688
689    #[doc(hidden)]
690    pub fn too_few_values<U>(
691        arg: &AnyArg,
692        min_vals: u64,
693        curr_vals: usize,
694        usage: U,
695        color: ColorWhen,
696    ) -> Self
697    where
698        U: Display,
699    {
700        let c = Colorizer::new(ColorizerOption {
701            use_stderr: true,
702            when: color,
703        });
704        Error {
705            message: format!(
706                "{} The argument '{}' requires at least {} values, but only {} w{} \
707                 provided\n\n\
708                 {}\n\n\
709                 For more information try {}",
710                c.error("error:"),
711                c.warning(arg.to_string()),
712                c.warning(min_vals.to_string()),
713                c.warning(curr_vals.to_string()),
714                if curr_vals > 1 { "ere" } else { "as" },
715                usage,
716                c.good("--help")
717            ),
718            kind: ErrorKind::TooFewValues,
719            info: Some(vec![arg.name().to_owned()]),
720        }
721    }
722
723    #[doc(hidden)]
724    pub fn value_validation(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self
725    {
726        let c = Colorizer::new(ColorizerOption {
727            use_stderr: true,
728            when: color,
729        });
730        Error {
731            message: format!(
732                "{} Invalid value{}: {}",
733                c.error("error:"),
734                if let Some(a) = arg {
735                    format!(" for '{}'", c.warning(a.to_string()))
736                } else {
737                    "".to_string()
738                },
739                err
740            ),
741            kind: ErrorKind::ValueValidation,
742            info: None,
743        }
744    }
745
746    #[doc(hidden)]
747    pub fn value_validation_auto(err: String) -> Self {
748        let n: Option<&AnyArg> = None;
749        Error::value_validation(n, err, ColorWhen::Auto)
750    }
751
752    #[doc(hidden)]
753    pub fn wrong_number_of_values<S, U>(
754        arg: &AnyArg,
755        num_vals: u64,
756        curr_vals: usize,
757        suffix: S,
758        usage: U,
759        color: ColorWhen,
760    ) -> Self
761    where
762        S: Display,
763        U: Display,
764    {
765        let c = Colorizer::new(ColorizerOption {
766            use_stderr: true,
767            when: color,
768        });
769        Error {
770            message: format!(
771                "{} The argument '{}' requires {} values, but {} w{} \
772                 provided\n\n\
773                 {}\n\n\
774                 For more information try {}",
775                c.error("error:"),
776                c.warning(arg.to_string()),
777                c.warning(num_vals.to_string()),
778                c.warning(curr_vals.to_string()),
779                suffix,
780                usage,
781                c.good("--help")
782            ),
783            kind: ErrorKind::WrongNumberOfValues,
784            info: Some(vec![arg.name().to_owned()]),
785        }
786    }
787
788    #[doc(hidden)]
789    pub fn unexpected_multiple_usage<U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
790    where
791        U: Display,
792    {
793        let c = Colorizer::new(ColorizerOption {
794            use_stderr: true,
795            when: color,
796        });
797        Error {
798            message: format!(
799                "{} The argument '{}' was provided more than once, but cannot \
800                 be used multiple times\n\n\
801                 {}\n\n\
802                 For more information try {}",
803                c.error("error:"),
804                c.warning(arg.to_string()),
805                usage,
806                c.good("--help")
807            ),
808            kind: ErrorKind::UnexpectedMultipleUsage,
809            info: Some(vec![arg.name().to_owned()]),
810        }
811    }
812
813    #[doc(hidden)]
814    pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self
815    where
816        A: Into<String>,
817        U: Display,
818    {
819        let a = arg.into();
820        let c = Colorizer::new(ColorizerOption {
821            use_stderr: true,
822            when: color,
823        });
824        Error {
825            message: format!(
826                "{} Found argument '{}' which wasn't expected, or isn't valid in \
827                 this context{}\n\
828                 {}\n\n\
829                 For more information try {}",
830                c.error("error:"),
831                c.warning(&*a),
832                if did_you_mean.is_empty() {
833                    "\n".to_owned()
834                } else {
835                    format!("{}\n", did_you_mean)
836                },
837                usage,
838                c.good("--help")
839            ),
840            kind: ErrorKind::UnknownArgument,
841            info: Some(vec![a]),
842        }
843    }
844
845    #[doc(hidden)]
846    pub fn io_error(e: &Error, color: ColorWhen) -> Self {
847        let c = Colorizer::new(ColorizerOption {
848            use_stderr: true,
849            when: color,
850        });
851        Error {
852            message: format!("{} {}", c.error("error:"), e.description()),
853            kind: ErrorKind::Io,
854            info: None,
855        }
856    }
857
858    #[doc(hidden)]
859    pub fn argument_not_found_auto<A>(arg: A) -> Self
860    where
861        A: Into<String>,
862    {
863        let a = arg.into();
864        let c = Colorizer::new(ColorizerOption {
865            use_stderr: true,
866            when: ColorWhen::Auto,
867        });
868        Error {
869            message: format!(
870                "{} The argument '{}' wasn't found",
871                c.error("error:"),
872                a.clone()
873            ),
874            kind: ErrorKind::ArgumentNotFound,
875            info: Some(vec![a]),
876        }
877    }
878
879    /// Create an error with a custom description.
880    ///
881    /// This can be used in combination with `Error::exit` to exit your program
882    /// with a custom error message.
883    pub fn with_description(description: &str, kind: ErrorKind) -> Self {
884        let c = Colorizer::new(ColorizerOption {
885            use_stderr: true,
886            when: ColorWhen::Auto,
887        });
888        Error {
889            message: format!("{} {}", c.error("error:"), description),
890            kind: kind,
891            info: None,
892        }
893    }
894}
895
896impl StdError for Error {
897    fn description(&self) -> &str { &*self.message }
898}
899
900impl Display for Error {
901    fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result { writeln!(f, "{}", self.message) }
902}
903
904impl From<io::Error> for Error {
905    fn from(e: io::Error) -> Self { Error::with_description(e.description(), ErrorKind::Io) }
906}
907
908impl From<std_fmt::Error> for Error {
909    fn from(e: std_fmt::Error) -> Self {
910        Error::with_description(e.description(), ErrorKind::Format)
911    }
912}