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