1 //! Error reporting
2 #![allow(deprecated)]
3 
4 // Std
5 use std::{
6     borrow::Cow,
7     convert::From,
8     error,
9     fmt::{self, Debug, Display, Formatter},
10     io::{self, BufRead},
11     result::Result as StdResult,
12 };
13 
14 // Internal
15 use crate::output::fmt::Colorizer;
16 use crate::output::fmt::Stream;
17 use crate::parser::features::suggestions;
18 use crate::util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE};
19 use crate::AppSettings;
20 use crate::Command;
21 
22 mod context;
23 mod kind;
24 
25 pub use context::ContextKind;
26 pub use context::ContextValue;
27 pub use kind::ErrorKind;
28 
29 /// Short hand for [`Result`] type
30 ///
31 /// [`Result`]: std::result::Result
32 pub type Result<T, E = Error> = StdResult<T, E>;
33 
34 /// Command Line Argument Parser Error
35 ///
36 /// See [`Command::error`] to create an error.
37 ///
38 /// [`Command::error`]: crate::Command::error
39 #[derive(Debug)]
40 pub struct Error {
41     inner: Box<ErrorInner>,
42     /// Deprecated, replaced with [`Error::kind()`]
43     #[cfg_attr(
44         feature = "deprecated",
45         deprecated(since = "3.1.0", note = "Replaced with `Error::kind()`")
46     )]
47     pub kind: ErrorKind,
48     /// Deprecated, replaced with [`Error::context()`]
49     #[cfg_attr(
50         feature = "deprecated",
51         deprecated(since = "3.1.0", note = "Replaced with `Error::context()`")
52     )]
53     pub info: Vec<String>,
54 }
55 
56 #[derive(Debug)]
57 struct ErrorInner {
58     kind: ErrorKind,
59     context: Vec<(ContextKind, ContextValue)>,
60     message: Option<Message>,
61     source: Option<Box<dyn error::Error + Send + Sync>>,
62     help_flag: Option<&'static str>,
63     color_when: ColorChoice,
64     wait_on_exit: bool,
65     backtrace: Option<Backtrace>,
66 }
67 
68 impl Error {
69     /// Create an unformatted error
70     ///
71     /// This is for you need to pass the error up to
72     /// a place that has access to the `Command` at which point you can call [`Error::format`].
73     ///
74     /// Prefer [`Command::error`] for generating errors.
75     ///
76     /// [`Command::error`]: crate::Command::error
raw(kind: ErrorKind, message: impl std::fmt::Display) -> Self77     pub fn raw(kind: ErrorKind, message: impl std::fmt::Display) -> Self {
78         Self::new(kind).set_message(message.to_string())
79     }
80 
81     /// Format the existing message with the Command's context
82     #[must_use]
format(mut self, cmd: &mut Command) -> Self83     pub fn format(mut self, cmd: &mut Command) -> Self {
84         cmd._build_self();
85         let usage = cmd.render_usage();
86         if let Some(message) = self.inner.message.as_mut() {
87             message.format(cmd, usage);
88         }
89         self.with_cmd(cmd)
90     }
91 
92     /// Type of error for programmatic processing
kind(&self) -> ErrorKind93     pub fn kind(&self) -> ErrorKind {
94         self.inner.kind
95     }
96 
97     /// Additional information to further qualify the error
context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)>98     pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> {
99         self.inner.context.iter().map(|(k, v)| (*k, v))
100     }
101 
102     /// Should the message be written to `stdout` or not?
103     #[inline]
use_stderr(&self) -> bool104     pub fn use_stderr(&self) -> bool {
105         self.stream() == Stream::Stderr
106     }
107 
stream(&self) -> Stream108     pub(crate) fn stream(&self) -> Stream {
109         match self.kind() {
110             ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout,
111             _ => Stream::Stderr,
112         }
113     }
114 
115     /// Prints the error and exits.
116     ///
117     /// Depending on the error kind, this either prints to `stderr` and exits with a status of `2`
118     /// or prints to `stdout` and exits with a status of `0`.
exit(&self) -> !119     pub fn exit(&self) -> ! {
120         if self.use_stderr() {
121             // Swallow broken pipe errors
122             let _ = self.print();
123 
124             if self.inner.wait_on_exit {
125                 wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
126                 let mut s = String::new();
127                 let i = io::stdin();
128                 i.lock().read_line(&mut s).unwrap();
129             }
130 
131             safe_exit(USAGE_CODE);
132         }
133 
134         // Swallow broken pipe errors
135         let _ = self.print();
136         safe_exit(SUCCESS_CODE)
137     }
138 
139     /// Prints formatted and colored error to `stdout` or `stderr` according to its error kind
140     ///
141     /// # Example
142     /// ```no_run
143     /// use clap::Command;
144     ///
145     /// match Command::new("Command").try_get_matches() {
146     ///     Ok(matches) => {
147     ///         // do_something
148     ///     },
149     ///     Err(err) => {
150     ///         err.print().expect("Error writing Error");
151     ///         // do_something
152     ///     },
153     /// };
154     /// ```
print(&self) -> io::Result<()>155     pub fn print(&self) -> io::Result<()> {
156         self.formatted().print()
157     }
158 
159     /// Deprecated, replaced with [`Command::error`]
160     ///
161     /// [`Command::error`]: crate::Command::error
162     #[cfg_attr(
163         feature = "deprecated",
164         deprecated(since = "3.0.0", note = "Replaced with `Command::error`")
165     )]
166     #[doc(hidden)]
with_description(description: String, kind: ErrorKind) -> Self167     pub fn with_description(description: String, kind: ErrorKind) -> Self {
168         Error::raw(kind, description)
169     }
170 
new(kind: ErrorKind) -> Self171     fn new(kind: ErrorKind) -> Self {
172         Self {
173             inner: Box::new(ErrorInner {
174                 kind,
175                 context: Vec::new(),
176                 message: None,
177                 source: None,
178                 help_flag: None,
179                 color_when: ColorChoice::Never,
180                 wait_on_exit: false,
181                 backtrace: Backtrace::new(),
182             }),
183             kind,
184             info: vec![],
185         }
186     }
187 
188     #[inline(never)]
for_app(kind: ErrorKind, cmd: &Command, colorizer: Colorizer, info: Vec<String>) -> Self189     fn for_app(kind: ErrorKind, cmd: &Command, colorizer: Colorizer, info: Vec<String>) -> Self {
190         Self::new(kind)
191             .set_message(colorizer)
192             .with_cmd(cmd)
193             .set_info(info)
194     }
195 
with_cmd(self, cmd: &Command) -> Self196     pub(crate) fn with_cmd(self, cmd: &Command) -> Self {
197         self.set_wait_on_exit(cmd.is_set(AppSettings::WaitOnError))
198             .set_color(cmd.get_color())
199             .set_help_flag(get_help_flag(cmd))
200     }
201 
set_message(mut self, message: impl Into<Message>) -> Self202     pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self {
203         self.inner.message = Some(message.into());
204         self
205     }
206 
set_info(mut self, info: Vec<String>) -> Self207     pub(crate) fn set_info(mut self, info: Vec<String>) -> Self {
208         self.info = info;
209         self
210     }
211 
set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self212     pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
213         self.inner.source = Some(source);
214         self
215     }
216 
set_color(mut self, color_when: ColorChoice) -> Self217     pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self {
218         self.inner.color_when = color_when;
219         self
220     }
221 
set_help_flag(mut self, help_flag: Option<&'static str>) -> Self222     pub(crate) fn set_help_flag(mut self, help_flag: Option<&'static str>) -> Self {
223         self.inner.help_flag = help_flag;
224         self
225     }
226 
set_wait_on_exit(mut self, yes: bool) -> Self227     pub(crate) fn set_wait_on_exit(mut self, yes: bool) -> Self {
228         self.inner.wait_on_exit = yes;
229         self
230     }
231 
232     /// Does not verify if `ContextKind` is already present
233     #[inline(never)]
insert_context_unchecked( mut self, kind: ContextKind, value: ContextValue, ) -> Self234     pub(crate) fn insert_context_unchecked(
235         mut self,
236         kind: ContextKind,
237         value: ContextValue,
238     ) -> Self {
239         self.inner.context.push((kind, value));
240         self
241     }
242 
243     /// Does not verify if `ContextKind` is already present
244     #[inline(never)]
extend_context_unchecked<const N: usize>( mut self, context: [(ContextKind, ContextValue); N], ) -> Self245     pub(crate) fn extend_context_unchecked<const N: usize>(
246         mut self,
247         context: [(ContextKind, ContextValue); N],
248     ) -> Self {
249         self.inner.context.extend(context);
250         self
251     }
252 
253     #[inline(never)]
get_context(&self, kind: ContextKind) -> Option<&ContextValue>254     fn get_context(&self, kind: ContextKind) -> Option<&ContextValue> {
255         self.inner
256             .context
257             .iter()
258             .find_map(|(k, v)| (*k == kind).then(|| v))
259     }
260 
display_help(cmd: &Command, colorizer: Colorizer) -> Self261     pub(crate) fn display_help(cmd: &Command, colorizer: Colorizer) -> Self {
262         Self::for_app(ErrorKind::DisplayHelp, cmd, colorizer, vec![])
263     }
264 
display_help_error(cmd: &Command, colorizer: Colorizer) -> Self265     pub(crate) fn display_help_error(cmd: &Command, colorizer: Colorizer) -> Self {
266         Self::for_app(
267             ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
268             cmd,
269             colorizer,
270             vec![],
271         )
272     }
273 
display_version(cmd: &Command, colorizer: Colorizer) -> Self274     pub(crate) fn display_version(cmd: &Command, colorizer: Colorizer) -> Self {
275         Self::for_app(ErrorKind::DisplayVersion, cmd, colorizer, vec![])
276     }
277 
argument_conflict( cmd: &Command, arg: String, mut others: Vec<String>, usage: String, ) -> Self278     pub(crate) fn argument_conflict(
279         cmd: &Command,
280         arg: String,
281         mut others: Vec<String>,
282         usage: String,
283     ) -> Self {
284         let info = others.clone();
285         let others = match others.len() {
286             0 => ContextValue::None,
287             1 => ContextValue::String(others.pop().unwrap()),
288             _ => ContextValue::Strings(others),
289         };
290         Self::new(ErrorKind::ArgumentConflict)
291             .with_cmd(cmd)
292             .set_info(info)
293             .extend_context_unchecked([
294                 (ContextKind::InvalidArg, ContextValue::String(arg)),
295                 (ContextKind::PriorArg, others),
296                 (ContextKind::Usage, ContextValue::String(usage)),
297             ])
298     }
299 
empty_value(cmd: &Command, good_vals: &[&str], arg: String) -> Self300     pub(crate) fn empty_value(cmd: &Command, good_vals: &[&str], arg: String) -> Self {
301         let info = vec![arg.clone()];
302         let mut err = Self::new(ErrorKind::EmptyValue)
303             .with_cmd(cmd)
304             .set_info(info)
305             .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
306         if !good_vals.is_empty() {
307             err = err.insert_context_unchecked(
308                 ContextKind::ValidValue,
309                 ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()),
310             );
311         }
312         err
313     }
314 
no_equals(cmd: &Command, arg: String, usage: String) -> Self315     pub(crate) fn no_equals(cmd: &Command, arg: String, usage: String) -> Self {
316         let info = vec![arg.clone()];
317         Self::new(ErrorKind::NoEquals)
318             .with_cmd(cmd)
319             .set_info(info)
320             .extend_context_unchecked([
321                 (ContextKind::InvalidArg, ContextValue::String(arg)),
322                 (ContextKind::Usage, ContextValue::String(usage)),
323             ])
324     }
325 
invalid_value( cmd: &Command, bad_val: String, good_vals: &[&str], arg: String, ) -> Self326     pub(crate) fn invalid_value(
327         cmd: &Command,
328         bad_val: String,
329         good_vals: &[&str],
330         arg: String,
331     ) -> Self {
332         let mut info = vec![arg.clone(), bad_val.clone()];
333         info.extend(good_vals.iter().map(|s| (*s).to_owned()));
334 
335         let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
336         let mut err = Self::new(ErrorKind::InvalidValue)
337             .with_cmd(cmd)
338             .set_info(info)
339             .extend_context_unchecked([
340                 (ContextKind::InvalidArg, ContextValue::String(arg)),
341                 (ContextKind::InvalidValue, ContextValue::String(bad_val)),
342                 (
343                     ContextKind::ValidValue,
344                     ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()),
345                 ),
346             ]);
347         if let Some(suggestion) = suggestion {
348             err = err.insert_context_unchecked(
349                 ContextKind::SuggestedValue,
350                 ContextValue::String(suggestion),
351             );
352         }
353         err
354     }
355 
invalid_subcommand( cmd: &Command, subcmd: String, did_you_mean: String, name: String, usage: String, ) -> Self356     pub(crate) fn invalid_subcommand(
357         cmd: &Command,
358         subcmd: String,
359         did_you_mean: String,
360         name: String,
361         usage: String,
362     ) -> Self {
363         let info = vec![subcmd.clone()];
364         let suggestion = format!("{} -- {}", name, subcmd);
365         Self::new(ErrorKind::InvalidSubcommand)
366             .with_cmd(cmd)
367             .set_info(info)
368             .extend_context_unchecked([
369                 (ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
370                 (
371                     ContextKind::SuggestedSubcommand,
372                     ContextValue::String(did_you_mean),
373                 ),
374                 (
375                     ContextKind::SuggestedCommand,
376                     ContextValue::String(suggestion),
377                 ),
378                 (ContextKind::Usage, ContextValue::String(usage)),
379             ])
380     }
381 
unrecognized_subcommand(cmd: &Command, subcmd: String, usage: String) -> Self382     pub(crate) fn unrecognized_subcommand(cmd: &Command, subcmd: String, usage: String) -> Self {
383         let info = vec![subcmd.clone()];
384         Self::new(ErrorKind::UnrecognizedSubcommand)
385             .with_cmd(cmd)
386             .set_info(info)
387             .extend_context_unchecked([
388                 (ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
389                 (ContextKind::Usage, ContextValue::String(usage)),
390             ])
391     }
392 
missing_required_argument( cmd: &Command, required: Vec<String>, usage: String, ) -> Self393     pub(crate) fn missing_required_argument(
394         cmd: &Command,
395         required: Vec<String>,
396         usage: String,
397     ) -> Self {
398         let info = required.clone();
399         Self::new(ErrorKind::MissingRequiredArgument)
400             .with_cmd(cmd)
401             .set_info(info)
402             .extend_context_unchecked([
403                 (ContextKind::InvalidArg, ContextValue::Strings(required)),
404                 (ContextKind::Usage, ContextValue::String(usage)),
405             ])
406     }
407 
missing_subcommand(cmd: &Command, name: String, usage: String) -> Self408     pub(crate) fn missing_subcommand(cmd: &Command, name: String, usage: String) -> Self {
409         let info = vec![];
410         Self::new(ErrorKind::MissingSubcommand)
411             .with_cmd(cmd)
412             .set_info(info)
413             .extend_context_unchecked([
414                 (ContextKind::InvalidSubcommand, ContextValue::String(name)),
415                 (ContextKind::Usage, ContextValue::String(usage)),
416             ])
417     }
418 
invalid_utf8(cmd: &Command, usage: String) -> Self419     pub(crate) fn invalid_utf8(cmd: &Command, usage: String) -> Self {
420         let info = vec![];
421         Self::new(ErrorKind::InvalidUtf8)
422             .with_cmd(cmd)
423             .set_info(info)
424             .extend_context_unchecked([(ContextKind::Usage, ContextValue::String(usage))])
425     }
426 
too_many_occurrences( cmd: &Command, arg: String, max_occurs: usize, curr_occurs: usize, usage: String, ) -> Self427     pub(crate) fn too_many_occurrences(
428         cmd: &Command,
429         arg: String,
430         max_occurs: usize,
431         curr_occurs: usize,
432         usage: String,
433     ) -> Self {
434         let info = vec![arg.clone(), curr_occurs.to_string(), max_occurs.to_string()];
435         Self::new(ErrorKind::TooManyOccurrences)
436             .with_cmd(cmd)
437             .set_info(info)
438             .extend_context_unchecked([
439                 (ContextKind::InvalidArg, ContextValue::String(arg)),
440                 (
441                     ContextKind::MaxOccurrences,
442                     ContextValue::Number(max_occurs as isize),
443                 ),
444                 (
445                     ContextKind::ActualNumValues,
446                     ContextValue::Number(curr_occurs as isize),
447                 ),
448                 (ContextKind::Usage, ContextValue::String(usage)),
449             ])
450     }
451 
too_many_values(cmd: &Command, val: String, arg: String, usage: String) -> Self452     pub(crate) fn too_many_values(cmd: &Command, val: String, arg: String, usage: String) -> Self {
453         let info = vec![arg.clone(), val.clone()];
454         Self::new(ErrorKind::TooManyValues)
455             .with_cmd(cmd)
456             .set_info(info)
457             .extend_context_unchecked([
458                 (ContextKind::InvalidArg, ContextValue::String(arg)),
459                 (ContextKind::InvalidValue, ContextValue::String(val)),
460                 (ContextKind::Usage, ContextValue::String(usage)),
461             ])
462     }
463 
too_few_values( cmd: &Command, arg: String, min_vals: usize, curr_vals: usize, usage: String, ) -> Self464     pub(crate) fn too_few_values(
465         cmd: &Command,
466         arg: String,
467         min_vals: usize,
468         curr_vals: usize,
469         usage: String,
470     ) -> Self {
471         let info = vec![arg.clone(), curr_vals.to_string(), min_vals.to_string()];
472         Self::new(ErrorKind::TooFewValues)
473             .with_cmd(cmd)
474             .set_info(info)
475             .extend_context_unchecked([
476                 (ContextKind::InvalidArg, ContextValue::String(arg)),
477                 (
478                     ContextKind::MinValues,
479                     ContextValue::Number(min_vals as isize),
480                 ),
481                 (
482                     ContextKind::ActualNumValues,
483                     ContextValue::Number(curr_vals as isize),
484                 ),
485                 (ContextKind::Usage, ContextValue::String(usage)),
486             ])
487     }
488 
value_validation( arg: String, val: String, err: Box<dyn error::Error + Send + Sync>, ) -> Self489     pub(crate) fn value_validation(
490         arg: String,
491         val: String,
492         err: Box<dyn error::Error + Send + Sync>,
493     ) -> Self {
494         let info = vec![arg.clone(), val.to_string(), err.to_string()];
495         Self::new(ErrorKind::ValueValidation)
496             .set_info(info)
497             .set_source(err)
498             .extend_context_unchecked([
499                 (ContextKind::InvalidArg, ContextValue::String(arg)),
500                 (ContextKind::InvalidValue, ContextValue::String(val)),
501             ])
502     }
503 
wrong_number_of_values( cmd: &Command, arg: String, num_vals: usize, curr_vals: usize, usage: String, ) -> Self504     pub(crate) fn wrong_number_of_values(
505         cmd: &Command,
506         arg: String,
507         num_vals: usize,
508         curr_vals: usize,
509         usage: String,
510     ) -> Self {
511         let info = vec![arg.clone(), curr_vals.to_string(), num_vals.to_string()];
512         Self::new(ErrorKind::WrongNumberOfValues)
513             .with_cmd(cmd)
514             .set_info(info)
515             .extend_context_unchecked([
516                 (ContextKind::InvalidArg, ContextValue::String(arg)),
517                 (
518                     ContextKind::ExpectedNumValues,
519                     ContextValue::Number(num_vals as isize),
520                 ),
521                 (
522                     ContextKind::ActualNumValues,
523                     ContextValue::Number(curr_vals as isize),
524                 ),
525                 (ContextKind::Usage, ContextValue::String(usage)),
526             ])
527     }
528 
unexpected_multiple_usage(cmd: &Command, arg: String, usage: String) -> Self529     pub(crate) fn unexpected_multiple_usage(cmd: &Command, arg: String, usage: String) -> Self {
530         let info = vec![arg.clone()];
531         Self::new(ErrorKind::UnexpectedMultipleUsage)
532             .with_cmd(cmd)
533             .set_info(info)
534             .extend_context_unchecked([
535                 (ContextKind::InvalidArg, ContextValue::String(arg)),
536                 (ContextKind::Usage, ContextValue::String(usage)),
537             ])
538     }
539 
unknown_argument( cmd: &Command, arg: String, did_you_mean: Option<(String, Option<String>)>, usage: String, ) -> Self540     pub(crate) fn unknown_argument(
541         cmd: &Command,
542         arg: String,
543         did_you_mean: Option<(String, Option<String>)>,
544         usage: String,
545     ) -> Self {
546         let info = vec![arg.clone()];
547         let mut err = Self::new(ErrorKind::UnknownArgument)
548             .with_cmd(cmd)
549             .set_info(info)
550             .extend_context_unchecked([
551                 (ContextKind::InvalidArg, ContextValue::String(arg)),
552                 (ContextKind::Usage, ContextValue::String(usage)),
553             ]);
554         if let Some((flag, sub)) = did_you_mean {
555             err = err.insert_context_unchecked(
556                 ContextKind::SuggestedArg,
557                 ContextValue::String(format!("--{}", flag)),
558             );
559             if let Some(sub) = sub {
560                 err = err.insert_context_unchecked(
561                     ContextKind::SuggestedSubcommand,
562                     ContextValue::String(sub),
563                 );
564             }
565         }
566         err
567     }
568 
unnecessary_double_dash(cmd: &Command, arg: String, usage: String) -> Self569     pub(crate) fn unnecessary_double_dash(cmd: &Command, arg: String, usage: String) -> Self {
570         let info = vec![arg.clone()];
571         Self::new(ErrorKind::UnknownArgument)
572             .with_cmd(cmd)
573             .set_info(info)
574             .extend_context_unchecked([
575                 (ContextKind::InvalidArg, ContextValue::String(arg)),
576                 (ContextKind::TrailingArg, ContextValue::Bool(true)),
577                 (ContextKind::Usage, ContextValue::String(usage)),
578             ])
579     }
580 
argument_not_found_auto(arg: String) -> Self581     pub(crate) fn argument_not_found_auto(arg: String) -> Self {
582         let info = vec![arg.clone()];
583         Self::new(ErrorKind::ArgumentNotFound)
584             .set_info(info)
585             .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))])
586     }
587 
formatted(&self) -> Cow<'_, Colorizer>588     fn formatted(&self) -> Cow<'_, Colorizer> {
589         if let Some(message) = self.inner.message.as_ref() {
590             message.formatted()
591         } else {
592             let mut c = Colorizer::new(self.stream(), self.inner.color_when);
593 
594             start_error(&mut c);
595 
596             if !self.write_dynamic_context(&mut c) {
597                 if let Some(msg) = self.kind().as_str() {
598                     c.none(msg.to_owned());
599                 } else if let Some(source) = self.inner.source.as_ref() {
600                     c.none(source.to_string());
601                 } else {
602                     c.none("Unknown cause");
603                 }
604             }
605 
606             let usage = self.get_context(ContextKind::Usage);
607             if let Some(ContextValue::String(usage)) = usage {
608                 put_usage(&mut c, usage);
609             }
610 
611             try_help(&mut c, self.inner.help_flag);
612 
613             Cow::Owned(c)
614         }
615     }
616 
617     #[must_use]
write_dynamic_context(&self, c: &mut Colorizer) -> bool618     fn write_dynamic_context(&self, c: &mut Colorizer) -> bool {
619         match self.kind() {
620             ErrorKind::ArgumentConflict => {
621                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
622                 let prior_arg = self.get_context(ContextKind::PriorArg);
623                 if let (Some(ContextValue::String(invalid_arg)), Some(prior_arg)) =
624                     (invalid_arg, prior_arg)
625                 {
626                     c.none("The argument '");
627                     c.warning(invalid_arg);
628                     c.none("' cannot be used with");
629 
630                     match prior_arg {
631                         ContextValue::Strings(values) => {
632                             c.none(":");
633                             for v in values {
634                                 c.none("\n    ");
635                                 c.warning(&**v);
636                             }
637                         }
638                         ContextValue::String(value) => {
639                             c.none(" '");
640                             c.warning(value);
641                             c.none("'");
642                         }
643                         _ => {
644                             c.none(" one or more of the other specified arguments");
645                         }
646                     }
647                     true
648                 } else {
649                     false
650                 }
651             }
652             ErrorKind::EmptyValue => {
653                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
654                 if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
655                     c.none("The argument '");
656                     c.warning(invalid_arg);
657                     c.none("' requires a value but none was supplied");
658 
659                     let possible_values = self.get_context(ContextKind::ValidValue);
660                     if let Some(ContextValue::Strings(possible_values)) = possible_values {
661                         c.none("\n\t[possible values: ");
662                         if let Some((last, elements)) = possible_values.split_last() {
663                             for v in elements {
664                                 c.good(escape(v));
665                                 c.none(", ");
666                             }
667                             c.good(escape(last));
668                         }
669                         c.none("]");
670                     }
671                     true
672                 } else {
673                     false
674                 }
675             }
676             ErrorKind::NoEquals => {
677                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
678                 if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
679                     c.none("Equal sign is needed when assigning values to '");
680                     c.warning(invalid_arg);
681                     c.none("'.");
682                     true
683                 } else {
684                     false
685                 }
686             }
687             ErrorKind::InvalidValue => {
688                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
689                 let invalid_value = self.get_context(ContextKind::InvalidValue);
690                 if let (
691                     Some(ContextValue::String(invalid_arg)),
692                     Some(ContextValue::String(invalid_value)),
693                 ) = (invalid_arg, invalid_value)
694                 {
695                     c.none(quote(invalid_value));
696                     c.none(" isn't a valid value for '");
697                     c.warning(invalid_arg);
698                     c.none("'");
699 
700                     let possible_values = self.get_context(ContextKind::ValidValue);
701                     if let Some(ContextValue::Strings(possible_values)) = possible_values {
702                         c.none("\n\t[possible values: ");
703                         if let Some((last, elements)) = possible_values.split_last() {
704                             for v in elements {
705                                 c.good(escape(v));
706                                 c.none(", ");
707                             }
708                             c.good(escape(last));
709                         }
710                         c.none("]");
711                     }
712 
713                     let suggestion = self.get_context(ContextKind::SuggestedValue);
714                     if let Some(ContextValue::String(suggestion)) = suggestion {
715                         c.none("\n\n\tDid you mean ");
716                         c.good(quote(suggestion));
717                         c.none("?");
718                     }
719                     true
720                 } else {
721                     false
722                 }
723             }
724             ErrorKind::InvalidSubcommand => {
725                 let invalid_sub = self.get_context(ContextKind::InvalidSubcommand);
726                 if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
727                     c.none("The subcommand '");
728                     c.warning(invalid_sub);
729                     c.none("' wasn't recognized");
730 
731                     let valid_sub = self.get_context(ContextKind::SuggestedSubcommand);
732                     if let Some(ContextValue::String(valid_sub)) = valid_sub {
733                         c.none("\n\n\tDid you mean ");
734                         c.good(valid_sub);
735                         c.none("?");
736                     }
737 
738                     let suggestion = self.get_context(ContextKind::SuggestedCommand);
739                     if let Some(ContextValue::String(suggestion)) = suggestion {
740                         c.none(
741             "\n\nIf you believe you received this message in error, try re-running with '",
742         );
743                         c.good(suggestion);
744                         c.none("'");
745                     }
746                     true
747                 } else {
748                     false
749                 }
750             }
751             ErrorKind::UnrecognizedSubcommand => {
752                 let invalid_sub = self.get_context(ContextKind::InvalidSubcommand);
753                 if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
754                     c.none("The subcommand '");
755                     c.warning(invalid_sub);
756                     c.none("' wasn't recognized");
757                     true
758                 } else {
759                     false
760                 }
761             }
762             ErrorKind::MissingRequiredArgument => {
763                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
764                 if let Some(ContextValue::Strings(invalid_arg)) = invalid_arg {
765                     c.none("The following required arguments were not provided:");
766                     for v in invalid_arg {
767                         c.none("\n    ");
768                         c.good(&**v);
769                     }
770                     true
771                 } else {
772                     false
773                 }
774             }
775             ErrorKind::MissingSubcommand => {
776                 let invalid_sub = self.get_context(ContextKind::InvalidSubcommand);
777                 if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
778                     c.none("'");
779                     c.warning(invalid_sub);
780                     c.none("' requires a subcommand but one was not provided");
781                     true
782                 } else {
783                     false
784                 }
785             }
786             ErrorKind::InvalidUtf8 => false,
787             ErrorKind::TooManyOccurrences => {
788                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
789                 let actual_num_occurs = self.get_context(ContextKind::ActualNumOccurrences);
790                 let max_occurs = self.get_context(ContextKind::MaxOccurrences);
791                 if let (
792                     Some(ContextValue::String(invalid_arg)),
793                     Some(ContextValue::Number(actual_num_occurs)),
794                     Some(ContextValue::Number(max_occurs)),
795                 ) = (invalid_arg, actual_num_occurs, max_occurs)
796                 {
797                     let were_provided = Error::singular_or_plural(*actual_num_occurs as usize);
798                     c.none("The argument '");
799                     c.warning(invalid_arg);
800                     c.none("' allows at most ");
801                     c.warning(max_occurs.to_string());
802                     c.none(" occurrences but ");
803                     c.warning(actual_num_occurs.to_string());
804                     c.none(were_provided);
805                     true
806                 } else {
807                     false
808                 }
809             }
810             ErrorKind::TooManyValues => {
811                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
812                 let invalid_value = self.get_context(ContextKind::InvalidValue);
813                 if let (
814                     Some(ContextValue::String(invalid_arg)),
815                     Some(ContextValue::String(invalid_value)),
816                 ) = (invalid_arg, invalid_value)
817                 {
818                     c.none("The value '");
819                     c.warning(invalid_value);
820                     c.none("' was provided to '");
821                     c.warning(invalid_arg);
822                     c.none("' but it wasn't expecting any more values");
823                     true
824                 } else {
825                     false
826                 }
827             }
828             ErrorKind::TooFewValues => {
829                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
830                 let actual_num_values = self.get_context(ContextKind::ActualNumValues);
831                 let min_values = self.get_context(ContextKind::MinValues);
832                 if let (
833                     Some(ContextValue::String(invalid_arg)),
834                     Some(ContextValue::Number(actual_num_values)),
835                     Some(ContextValue::Number(min_values)),
836                 ) = (invalid_arg, actual_num_values, min_values)
837                 {
838                     let were_provided = Error::singular_or_plural(*actual_num_values as usize);
839                     c.none("The argument '");
840                     c.warning(invalid_arg);
841                     c.none("' requires at least ");
842                     c.warning(min_values.to_string());
843                     c.none(" values but only ");
844                     c.warning(actual_num_values.to_string());
845                     c.none(were_provided);
846                     true
847                 } else {
848                     false
849                 }
850             }
851             ErrorKind::ValueValidation => {
852                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
853                 let invalid_value = self.get_context(ContextKind::InvalidValue);
854                 if let (
855                     Some(ContextValue::String(invalid_arg)),
856                     Some(ContextValue::String(invalid_value)),
857                 ) = (invalid_arg, invalid_value)
858                 {
859                     c.none("Invalid value ");
860                     c.warning(quote(invalid_value));
861                     c.none(" for '");
862                     c.warning(invalid_arg);
863                     if let Some(source) = self.inner.source.as_deref() {
864                         c.none("': ");
865                         c.none(source.to_string());
866                     } else {
867                         c.none("'");
868                     }
869                     true
870                 } else {
871                     false
872                 }
873             }
874             ErrorKind::WrongNumberOfValues => {
875                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
876                 let actual_num_values = self.get_context(ContextKind::ActualNumValues);
877                 let num_values = self.get_context(ContextKind::ExpectedNumValues);
878                 if let (
879                     Some(ContextValue::String(invalid_arg)),
880                     Some(ContextValue::Number(actual_num_values)),
881                     Some(ContextValue::Number(num_values)),
882                 ) = (invalid_arg, actual_num_values, num_values)
883                 {
884                     let were_provided = Error::singular_or_plural(*actual_num_values as usize);
885                     c.none("The argument '");
886                     c.warning(invalid_arg);
887                     c.none("' requires ");
888                     c.warning(num_values.to_string());
889                     c.none(" values, but ");
890                     c.warning(actual_num_values.to_string());
891                     c.none(were_provided);
892                     true
893                 } else {
894                     false
895                 }
896             }
897             ErrorKind::UnexpectedMultipleUsage => {
898                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
899                 if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
900                     c.none("The argument '");
901                     c.warning(invalid_arg.to_string());
902                     c.none("' was provided more than once, but cannot be used multiple times");
903                     true
904                 } else {
905                     false
906                 }
907             }
908             ErrorKind::UnknownArgument => {
909                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
910                 if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
911                     c.none("Found argument '");
912                     c.warning(invalid_arg.to_string());
913                     c.none("' which wasn't expected, or isn't valid in this context");
914 
915                     let valid_sub = self.get_context(ContextKind::SuggestedSubcommand);
916                     let valid_arg = self.get_context(ContextKind::SuggestedArg);
917                     match (valid_sub, valid_arg) {
918                         (
919                             Some(ContextValue::String(valid_sub)),
920                             Some(ContextValue::String(valid_arg)),
921                         ) => {
922                             c.none("\n\n\tDid you mean ");
923                             c.none("to put '");
924                             c.good(valid_arg);
925                             c.none("' after the subcommand '");
926                             c.good(valid_sub);
927                             c.none("'?");
928                         }
929                         (None, Some(ContextValue::String(valid_arg))) => {
930                             c.none("\n\n\tDid you mean '");
931                             c.good(valid_arg);
932                             c.none("'?");
933                         }
934                         (_, _) => {}
935                     }
936 
937                     let invalid_arg = self.get_context(ContextKind::InvalidArg);
938                     if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
939                         if invalid_arg.starts_with('-') {
940                             c.none(format!(
941                                 "\n\n\tIf you tried to supply `{}` as a value rather than a flag, use `-- {}`",
942                                 invalid_arg, invalid_arg
943                             ));
944                         }
945 
946                         let trailing_arg = self.get_context(ContextKind::TrailingArg);
947                         if trailing_arg == Some(&ContextValue::Bool(true)) {
948                             c.none(format!(
949                             "\n\n\tIf you tried to supply `{}` as a subcommand, remove the '--' before it.",
950                             invalid_arg
951                         ));
952                         }
953                     }
954                     true
955                 } else {
956                     false
957                 }
958             }
959             ErrorKind::ArgumentNotFound => {
960                 let invalid_arg = self.get_context(ContextKind::InvalidArg);
961                 if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
962                     c.none("The argument '");
963                     c.warning(invalid_arg.to_string());
964                     c.none("' wasn't found");
965                     true
966                 } else {
967                     false
968                 }
969             }
970             ErrorKind::DisplayHelp
971             | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
972             | ErrorKind::DisplayVersion
973             | ErrorKind::Io
974             | ErrorKind::Format => false,
975         }
976     }
977 
978     /// Returns the singular or plural form on the verb to be based on the argument's value.
singular_or_plural(n: usize) -> &'static str979     fn singular_or_plural(n: usize) -> &'static str {
980         if n > 1 {
981             " were provided"
982         } else {
983             " was provided"
984         }
985     }
986 }
987 
988 impl From<io::Error> for Error {
from(e: io::Error) -> Self989     fn from(e: io::Error) -> Self {
990         Error::raw(ErrorKind::Io, e)
991     }
992 }
993 
994 impl From<fmt::Error> for Error {
from(e: fmt::Error) -> Self995     fn from(e: fmt::Error) -> Self {
996         Error::raw(ErrorKind::Format, e)
997     }
998 }
999 
1000 impl error::Error for Error {
1001     #[allow(trivial_casts)]
source(&self) -> Option<&(dyn error::Error + 'static)>1002     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1003         self.inner.source.as_ref().map(|e| e.as_ref() as _)
1004     }
1005 }
1006 
1007 impl Display for Error {
fmt(&self, f: &mut Formatter) -> fmt::Result1008     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1009         // Assuming `self.message` already has a trailing newline, from `try_help` or similar
1010         write!(f, "{}", self.formatted())?;
1011         if let Some(backtrace) = self.inner.backtrace.as_ref() {
1012             writeln!(f)?;
1013             writeln!(f, "Backtrace:")?;
1014             writeln!(f, "{}", backtrace)?;
1015         }
1016         Ok(())
1017     }
1018 }
1019 
start_error(c: &mut Colorizer)1020 fn start_error(c: &mut Colorizer) {
1021     c.error("error:");
1022     c.none(" ");
1023 }
1024 
put_usage(c: &mut Colorizer, usage: impl Into<String>)1025 fn put_usage(c: &mut Colorizer, usage: impl Into<String>) {
1026     c.none("\n\n");
1027     c.none(usage);
1028 }
1029 
get_help_flag(cmd: &Command) -> Option<&'static str>1030 fn get_help_flag(cmd: &Command) -> Option<&'static str> {
1031     if !cmd.is_disable_help_flag_set() {
1032         Some("--help")
1033     } else if cmd.has_subcommands() && !cmd.is_disable_help_subcommand_set() {
1034         Some("help")
1035     } else {
1036         None
1037     }
1038 }
1039 
try_help(c: &mut Colorizer, help: Option<&str>)1040 fn try_help(c: &mut Colorizer, help: Option<&str>) {
1041     if let Some(help) = help {
1042         c.none("\n\nFor more information try ");
1043         c.good(help);
1044         c.none("\n");
1045     } else {
1046         c.none("\n");
1047     }
1048 }
1049 
quote(s: impl AsRef<str>) -> String1050 fn quote(s: impl AsRef<str>) -> String {
1051     let s = s.as_ref();
1052     format!("{:?}", s)
1053 }
1054 
escape(s: impl AsRef<str>) -> String1055 fn escape(s: impl AsRef<str>) -> String {
1056     let s = s.as_ref();
1057     if s.contains(char::is_whitespace) {
1058         quote(s)
1059     } else {
1060         s.to_owned()
1061     }
1062 }
1063 
1064 #[derive(Clone, Debug)]
1065 pub(crate) enum Message {
1066     Raw(String),
1067     Formatted(Colorizer),
1068 }
1069 
1070 impl Message {
format(&mut self, cmd: &Command, usage: String)1071     fn format(&mut self, cmd: &Command, usage: String) {
1072         match self {
1073             Message::Raw(s) => {
1074                 let mut c = Colorizer::new(Stream::Stderr, cmd.get_color());
1075 
1076                 let mut message = String::new();
1077                 std::mem::swap(s, &mut message);
1078                 start_error(&mut c);
1079                 c.none(message);
1080                 put_usage(&mut c, usage);
1081                 try_help(&mut c, get_help_flag(cmd));
1082                 *self = Self::Formatted(c);
1083             }
1084             Message::Formatted(_) => {}
1085         }
1086     }
1087 
formatted(&self) -> Cow<Colorizer>1088     fn formatted(&self) -> Cow<Colorizer> {
1089         match self {
1090             Message::Raw(s) => {
1091                 let mut c = Colorizer::new(Stream::Stderr, ColorChoice::Never);
1092                 start_error(&mut c);
1093                 c.none(s);
1094                 Cow::Owned(c)
1095             }
1096             Message::Formatted(c) => Cow::Borrowed(c),
1097         }
1098     }
1099 }
1100 
1101 impl From<String> for Message {
from(inner: String) -> Self1102     fn from(inner: String) -> Self {
1103         Self::Raw(inner)
1104     }
1105 }
1106 
1107 impl From<Colorizer> for Message {
from(inner: Colorizer) -> Self1108     fn from(inner: Colorizer) -> Self {
1109         Self::Formatted(inner)
1110     }
1111 }
1112 
1113 #[cfg(feature = "debug")]
1114 #[derive(Debug)]
1115 struct Backtrace(backtrace::Backtrace);
1116 
1117 #[cfg(feature = "debug")]
1118 impl Backtrace {
new() -> Option<Self>1119     fn new() -> Option<Self> {
1120         Some(Self(backtrace::Backtrace::new()))
1121     }
1122 }
1123 
1124 #[cfg(feature = "debug")]
1125 impl Display for Backtrace {
fmt(&self, f: &mut Formatter) -> fmt::Result1126     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1127         // `backtrace::Backtrace` uses `Debug` instead of `Display`
1128         write!(f, "{:?}", self.0)
1129     }
1130 }
1131 
1132 #[cfg(not(feature = "debug"))]
1133 #[derive(Debug)]
1134 struct Backtrace;
1135 
1136 #[cfg(not(feature = "debug"))]
1137 impl Backtrace {
new() -> Option<Self>1138     fn new() -> Option<Self> {
1139         None
1140     }
1141 }
1142 
1143 #[cfg(not(feature = "debug"))]
1144 impl Display for Backtrace {
fmt(&self, _: &mut Formatter) -> fmt::Result1145     fn fmt(&self, _: &mut Formatter) -> fmt::Result {
1146         Ok(())
1147     }
1148 }
1149 
1150 #[test]
check_auto_traits()1151 fn check_auto_traits() {
1152     static_assertions::assert_impl_all!(Error: Send, Sync, Unpin);
1153 }
1154