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}