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}