9 fmt
::{self, Debug, Display, Formatter}
,
11 result
::Result
as StdResult
,
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
;
25 pub use context
::ContextKind
;
26 pub use context
::ContextValue
;
27 pub use kind
::ErrorKind
;
29 /// Short hand for [`Result`] type
31 /// [`Result`]: std::result::Result
32 pub type Result
<T
, E
= Error
> = StdResult
<T
, E
>;
34 /// Command Line Argument Parser Error
36 /// See [`Command::error`] to create an error.
38 /// [`Command::error`]: crate::Command::error
41 inner
: Box
<ErrorInner
>,
42 /// Deprecated, replaced with [`Error::kind()`]
44 feature
= "deprecated",
45 deprecated(since
= "3.1.0", note
= "Replaced with `Error::kind()`")
48 /// Deprecated, replaced with [`Error::context()`]
50 feature
= "deprecated",
51 deprecated(since
= "3.1.0", note
= "Replaced with `Error::context()`")
53 pub info
: Vec
<String
>,
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
,
65 backtrace
: Option
<Backtrace
>,
69 /// Create an unformatted error
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`].
74 /// Prefer [`Command::error`] for generating errors.
76 /// [`Command::error`]: crate::Command::error
77 pub fn raw(kind
: ErrorKind
, message
: impl std
::fmt
::Display
) -> Self {
78 Self::new(kind
).set_message(message
.to_string())
81 /// Format the existing message with the Command's context
83 pub fn format(mut self, cmd
: &mut Command
) -> Self {
85 let usage
= cmd
.render_usage();
86 if let Some(message
) = self.inner
.message
.as_mut() {
87 message
.format(cmd
, usage
);
92 /// Type of error for programmatic processing
93 pub fn kind(&self) -> ErrorKind
{
97 /// Additional information to further qualify the error
98 pub fn context(&self) -> impl Iterator
<Item
= (ContextKind
, &ContextValue
)> {
99 self.inner
.context
.iter().map(|(k
, v
)| (*k
, v
))
102 /// Should the message be written to `stdout` or not?
104 pub fn use_stderr(&self) -> bool
{
105 self.stream() == Stream
::Stderr
108 pub(crate) fn stream(&self) -> Stream
{
110 ErrorKind
::DisplayHelp
| ErrorKind
::DisplayVersion
=> Stream
::Stdout
,
115 /// Prints the error and exits.
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`.
119 pub fn exit(&self) -> ! {
120 if self.use_stderr() {
121 // Swallow broken pipe errors
122 let _
= self.print();
124 if self.inner
.wait_on_exit
{
125 wlnerr
!("\nPress [ENTER] / [RETURN] to continue...");
126 let mut s
= String
::new();
128 i
.lock().read_line(&mut s
).unwrap();
131 safe_exit(USAGE_CODE
);
134 // Swallow broken pipe errors
135 let _
= self.print();
136 safe_exit(SUCCESS_CODE
)
139 /// Prints formatted and colored error to `stdout` or `stderr` according to its error kind
143 /// use clap::Command;
145 /// match Command::new("Command").try_get_matches() {
150 /// err.print().expect("Error writing Error");
155 pub fn print(&self) -> io
::Result
<()> {
156 self.formatted().print()
159 /// Deprecated, replaced with [`Command::error`]
161 /// [`Command::error`]: crate::Command::error
163 feature
= "deprecated",
164 deprecated(since
= "3.0.0", note
= "Replaced with `Command::error`")
167 pub fn with_description(description
: String
, kind
: ErrorKind
) -> Self {
168 Error
::raw(kind
, description
)
171 fn new(kind
: ErrorKind
) -> Self {
173 inner
: Box
::new(ErrorInner
{
179 color_when
: ColorChoice
::Never
,
181 backtrace
: Backtrace
::new(),
189 fn for_app(kind
: ErrorKind
, cmd
: &Command
, colorizer
: Colorizer
, info
: Vec
<String
>) -> Self {
191 .set_message(colorizer
)
196 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
))
202 pub(crate) fn set_message(mut self, message
: impl Into
<Message
>) -> Self {
203 self.inner
.message
= Some(message
.into());
207 pub(crate) fn set_info(mut self, info
: Vec
<String
>) -> Self {
212 pub(crate) fn set_source(mut self, source
: Box
<dyn error
::Error
+ Send
+ Sync
>) -> Self {
213 self.inner
.source
= Some(source
);
217 pub(crate) fn set_color(mut self, color_when
: ColorChoice
) -> Self {
218 self.inner
.color_when
= color_when
;
222 pub(crate) fn set_help_flag(mut self, help_flag
: Option
<&'
static str>) -> Self {
223 self.inner
.help_flag
= help_flag
;
227 pub(crate) fn set_wait_on_exit(mut self, yes
: bool
) -> Self {
228 self.inner
.wait_on_exit
= yes
;
232 /// Does not verify if `ContextKind` is already present
234 pub(crate) fn insert_context_unchecked(
239 self.inner
.context
.push((kind
, value
));
243 /// Does not verify if `ContextKind` is already present
245 pub(crate) fn extend_context_unchecked
<const N
: usize>(
247 context
: [(ContextKind
, ContextValue
); N
],
249 self.inner
.context
.extend(context
);
254 fn get_context(&self, kind
: ContextKind
) -> Option
<&ContextValue
> {
258 .find_map(|(k
, v
)| (*k
== kind
).then(|| v
))
261 pub(crate) fn display_help(cmd
: &Command
, colorizer
: Colorizer
) -> Self {
262 Self::for_app(ErrorKind
::DisplayHelp
, cmd
, colorizer
, vec
![])
265 pub(crate) fn display_help_error(cmd
: &Command
, colorizer
: Colorizer
) -> Self {
267 ErrorKind
::DisplayHelpOnMissingArgumentOrSubcommand
,
274 pub(crate) fn display_version(cmd
: &Command
, colorizer
: Colorizer
) -> Self {
275 Self::for_app(ErrorKind
::DisplayVersion
, cmd
, colorizer
, vec
![])
278 pub(crate) fn argument_conflict(
281 mut others
: Vec
<String
>,
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
),
290 Self::new(ErrorKind
::ArgumentConflict
)
293 .extend_context_unchecked([
294 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
295 (ContextKind
::PriorArg
, others
),
296 (ContextKind
::Usage
, ContextValue
::String(usage
)),
300 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
)
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()),
315 pub(crate) fn no_equals(cmd
: &Command
, arg
: String
, usage
: String
) -> Self {
316 let info
= vec
![arg
.clone()];
317 Self::new(ErrorKind
::NoEquals
)
320 .extend_context_unchecked([
321 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
322 (ContextKind
::Usage
, ContextValue
::String(usage
)),
326 pub(crate) fn invalid_value(
332 let mut info
= vec
![arg
.clone(), bad_val
.clone()];
333 info
.extend(good_vals
.iter().map(|s
| (*s
).to_owned()));
335 let suggestion
= suggestions
::did_you_mean(&bad_val
, good_vals
.iter()).pop();
336 let mut err
= Self::new(ErrorKind
::InvalidValue
)
339 .extend_context_unchecked([
340 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
341 (ContextKind
::InvalidValue
, ContextValue
::String(bad_val
)),
343 ContextKind
::ValidValue
,
344 ContextValue
::Strings(good_vals
.iter().map(|s
| (*s
).to_owned()).collect()),
347 if let Some(suggestion
) = suggestion
{
348 err
= err
.insert_context_unchecked(
349 ContextKind
::SuggestedValue
,
350 ContextValue
::String(suggestion
),
356 pub(crate) fn invalid_subcommand(
359 did_you_mean
: String
,
363 let info
= vec
![subcmd
.clone()];
364 let suggestion
= format
!("{} -- {}", name
, subcmd
);
365 Self::new(ErrorKind
::InvalidSubcommand
)
368 .extend_context_unchecked([
369 (ContextKind
::InvalidSubcommand
, ContextValue
::String(subcmd
)),
371 ContextKind
::SuggestedSubcommand
,
372 ContextValue
::String(did_you_mean
),
375 ContextKind
::SuggestedCommand
,
376 ContextValue
::String(suggestion
),
378 (ContextKind
::Usage
, ContextValue
::String(usage
)),
382 pub(crate) fn unrecognized_subcommand(cmd
: &Command
, subcmd
: String
, usage
: String
) -> Self {
383 let info
= vec
![subcmd
.clone()];
384 Self::new(ErrorKind
::UnrecognizedSubcommand
)
387 .extend_context_unchecked([
388 (ContextKind
::InvalidSubcommand
, ContextValue
::String(subcmd
)),
389 (ContextKind
::Usage
, ContextValue
::String(usage
)),
393 pub(crate) fn missing_required_argument(
395 required
: Vec
<String
>,
398 let info
= required
.clone();
399 Self::new(ErrorKind
::MissingRequiredArgument
)
402 .extend_context_unchecked([
403 (ContextKind
::InvalidArg
, ContextValue
::Strings(required
)),
404 (ContextKind
::Usage
, ContextValue
::String(usage
)),
408 pub(crate) fn missing_subcommand(cmd
: &Command
, name
: String
, usage
: String
) -> Self {
410 Self::new(ErrorKind
::MissingSubcommand
)
413 .extend_context_unchecked([
414 (ContextKind
::InvalidSubcommand
, ContextValue
::String(name
)),
415 (ContextKind
::Usage
, ContextValue
::String(usage
)),
419 pub(crate) fn invalid_utf8(cmd
: &Command
, usage
: String
) -> Self {
421 Self::new(ErrorKind
::InvalidUtf8
)
424 .extend_context_unchecked([(ContextKind
::Usage
, ContextValue
::String(usage
))])
427 pub(crate) fn too_many_occurrences(
434 let info
= vec
![arg
.clone(), curr_occurs
.to_string(), max_occurs
.to_string()];
435 Self::new(ErrorKind
::TooManyOccurrences
)
438 .extend_context_unchecked([
439 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
441 ContextKind
::MaxOccurrences
,
442 ContextValue
::Number(max_occurs
as isize),
445 ContextKind
::ActualNumValues
,
446 ContextValue
::Number(curr_occurs
as isize),
448 (ContextKind
::Usage
, ContextValue
::String(usage
)),
452 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
)
457 .extend_context_unchecked([
458 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
459 (ContextKind
::InvalidValue
, ContextValue
::String(val
)),
460 (ContextKind
::Usage
, ContextValue
::String(usage
)),
464 pub(crate) fn too_few_values(
471 let info
= vec
![arg
.clone(), curr_vals
.to_string(), min_vals
.to_string()];
472 Self::new(ErrorKind
::TooFewValues
)
475 .extend_context_unchecked([
476 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
478 ContextKind
::MinValues
,
479 ContextValue
::Number(min_vals
as isize),
482 ContextKind
::ActualNumValues
,
483 ContextValue
::Number(curr_vals
as isize),
485 (ContextKind
::Usage
, ContextValue
::String(usage
)),
489 pub(crate) fn value_validation(
492 err
: Box
<dyn error
::Error
+ Send
+ Sync
>,
494 let info
= vec
![arg
.clone(), val
.to_string(), err
.to_string()];
495 Self::new(ErrorKind
::ValueValidation
)
498 .extend_context_unchecked([
499 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
500 (ContextKind
::InvalidValue
, ContextValue
::String(val
)),
504 pub(crate) fn wrong_number_of_values(
511 let info
= vec
![arg
.clone(), curr_vals
.to_string(), num_vals
.to_string()];
512 Self::new(ErrorKind
::WrongNumberOfValues
)
515 .extend_context_unchecked([
516 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
518 ContextKind
::ExpectedNumValues
,
519 ContextValue
::Number(num_vals
as isize),
522 ContextKind
::ActualNumValues
,
523 ContextValue
::Number(curr_vals
as isize),
525 (ContextKind
::Usage
, ContextValue
::String(usage
)),
529 pub(crate) fn unexpected_multiple_usage(cmd
: &Command
, arg
: String
, usage
: String
) -> Self {
530 let info
= vec
![arg
.clone()];
531 Self::new(ErrorKind
::UnexpectedMultipleUsage
)
534 .extend_context_unchecked([
535 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
536 (ContextKind
::Usage
, ContextValue
::String(usage
)),
540 pub(crate) fn unknown_argument(
543 did_you_mean
: Option
<(String
, Option
<String
>)>,
546 let info
= vec
![arg
.clone()];
547 let mut err
= Self::new(ErrorKind
::UnknownArgument
)
550 .extend_context_unchecked([
551 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
552 (ContextKind
::Usage
, ContextValue
::String(usage
)),
554 if let Some((flag
, sub
)) = did_you_mean
{
555 err
= err
.insert_context_unchecked(
556 ContextKind
::SuggestedArg
,
557 ContextValue
::String(format
!("--{}", flag
)),
559 if let Some(sub
) = sub
{
560 err
= err
.insert_context_unchecked(
561 ContextKind
::SuggestedSubcommand
,
562 ContextValue
::String(sub
),
569 pub(crate) fn unnecessary_double_dash(cmd
: &Command
, arg
: String
, usage
: String
) -> Self {
570 let info
= vec
![arg
.clone()];
571 Self::new(ErrorKind
::UnknownArgument
)
574 .extend_context_unchecked([
575 (ContextKind
::InvalidArg
, ContextValue
::String(arg
)),
576 (ContextKind
::TrailingArg
, ContextValue
::Bool(true)),
577 (ContextKind
::Usage
, ContextValue
::String(usage
)),
581 pub(crate) fn argument_not_found_auto(arg
: String
) -> Self {
582 let info
= vec
![arg
.clone()];
583 Self::new(ErrorKind
::ArgumentNotFound
)
585 .extend_context_unchecked([(ContextKind
::InvalidArg
, ContextValue
::String(arg
))])
588 fn formatted(&self) -> Cow
<'_
, Colorizer
> {
589 if let Some(message
) = self.inner
.message
.as_ref() {
592 let mut c
= Colorizer
::new(self.stream(), self.inner
.color_when
);
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());
602 c
.none("Unknown cause");
606 let usage
= self.get_context(ContextKind
::Usage
);
607 if let Some(ContextValue
::String(usage
)) = usage
{
608 put_usage(&mut c
, usage
);
611 try_help(&mut c
, self.inner
.help_flag
);
618 fn write_dynamic_context(&self, c
: &mut Colorizer
) -> bool
{
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
)
626 c
.none("The argument '");
627 c
.warning(invalid_arg
);
628 c
.none("' cannot be used with");
631 ContextValue
::Strings(values
) => {
638 ContextValue
::String(value
) => {
644 c
.none(" one or more of the other specified arguments");
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");
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() {
667 c
.good(escape(last
));
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
);
687 ErrorKind
::InvalidValue
=> {
688 let invalid_arg
= self.get_context(ContextKind
::InvalidArg
);
689 let invalid_value
= self.get_context(ContextKind
::InvalidValue
);
691 Some(ContextValue
::String(invalid_arg
)),
692 Some(ContextValue
::String(invalid_value
)),
693 ) = (invalid_arg
, invalid_value
)
695 c
.none(quote(invalid_value
));
696 c
.none(" isn't a valid value for '");
697 c
.warning(invalid_arg
);
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() {
708 c
.good(escape(last
));
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
));
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");
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 ");
738 let suggestion
= self.get_context(ContextKind
::SuggestedCommand
);
739 if let Some(ContextValue
::String(suggestion
)) = suggestion
{
741 "\n\nIf you believe you received this message in error, try re-running with '",
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");
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
{
775 ErrorKind
::MissingSubcommand
=> {
776 let invalid_sub
= self.get_context(ContextKind
::InvalidSubcommand
);
777 if let Some(ContextValue
::String(invalid_sub
)) = invalid_sub
{
779 c
.warning(invalid_sub
);
780 c
.none("' requires a subcommand but one was not provided");
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
);
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
)
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
);
810 ErrorKind
::TooManyValues
=> {
811 let invalid_arg
= self.get_context(ContextKind
::InvalidArg
);
812 let invalid_value
= self.get_context(ContextKind
::InvalidValue
);
814 Some(ContextValue
::String(invalid_arg
)),
815 Some(ContextValue
::String(invalid_value
)),
816 ) = (invalid_arg
, invalid_value
)
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");
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
);
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
)
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
);
851 ErrorKind
::ValueValidation
=> {
852 let invalid_arg
= self.get_context(ContextKind
::InvalidArg
);
853 let invalid_value
= self.get_context(ContextKind
::InvalidValue
);
855 Some(ContextValue
::String(invalid_arg
)),
856 Some(ContextValue
::String(invalid_value
)),
857 ) = (invalid_arg
, invalid_value
)
859 c
.none("Invalid value ");
860 c
.warning(quote(invalid_value
));
862 c
.warning(invalid_arg
);
863 if let Some(source
) = self.inner
.source
.as_deref() {
865 c
.none(source
.to_string());
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
);
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
)
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
);
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");
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");
915 let valid_sub
= self.get_context(ContextKind
::SuggestedSubcommand
);
916 let valid_arg
= self.get_context(ContextKind
::SuggestedArg
);
917 match (valid_sub
, valid_arg
) {
919 Some(ContextValue
::String(valid_sub
)),
920 Some(ContextValue
::String(valid_arg
)),
922 c
.none("\n\n\tDid you mean ");
925 c
.none("' after the subcommand '");
929 (None
, Some(ContextValue
::String(valid_arg
))) => {
930 c
.none("\n\n\tDid you mean '");
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('
-'
) {
941 "\n\n\tIf you tried to supply `{}` as a value rather than a flag, use `-- {}`",
942 invalid_arg
, invalid_arg
946 let trailing_arg
= self.get_context(ContextKind
::TrailingArg
);
947 if trailing_arg
== Some(&ContextValue
::Bool(true)) {
949 "\n\n\tIf you tried to supply `{}` as a subcommand, remove the '--' before it.",
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");
970 ErrorKind
::DisplayHelp
971 | ErrorKind
::DisplayHelpOnMissingArgumentOrSubcommand
972 | ErrorKind
::DisplayVersion
974 | ErrorKind
::Format
=> false,
978 /// Returns the singular or plural form on the verb to be based on the argument's value.
979 fn singular_or_plural(n
: usize) -> &'
static str {
988 impl From
<io
::Error
> for Error
{
989 fn from(e
: io
::Error
) -> Self {
990 Error
::raw(ErrorKind
::Io
, e
)
994 impl From
<fmt
::Error
> for Error
{
995 fn from(e
: fmt
::Error
) -> Self {
996 Error
::raw(ErrorKind
::Format
, e
)
1000 impl error
::Error
for Error
{
1001 #[allow(trivial_casts)]
1002 fn source(&self) -> Option
<&(dyn error
::Error
+ '
static)> {
1003 self.inner
.source
.as_ref().map(|e
| e
.as_ref() as _
)
1007 impl Display
for Error
{
1008 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() {
1013 writeln
!(f
, "Backtrace:")?
;
1014 writeln
!(f
, "{}", backtrace
)?
;
1020 fn start_error(c
: &mut Colorizer
) {
1025 fn put_usage(c
: &mut Colorizer
, usage
: impl Into
<String
>) {
1030 fn get_help_flag(cmd
: &Command
) -> Option
<&'
static str> {
1031 if !cmd
.is_disable_help_flag_set() {
1033 } else if cmd
.has_subcommands() && !cmd
.is_disable_help_subcommand_set() {
1040 fn try_help(c
: &mut Colorizer
, help
: Option
<&str>) {
1041 if let Some(help
) = help
{
1042 c
.none("\n\nFor more information try ");
1050 fn quote(s
: impl AsRef
<str>) -> String
{
1055 fn escape(s
: impl AsRef
<str>) -> String
{
1057 if s
.contains(char::is_whitespace
) {
1064 #[derive(Clone, Debug)]
1065 pub(crate) enum Message
{
1067 Formatted(Colorizer
),
1071 fn format(&mut self, cmd
: &Command
, usage
: String
) {
1073 Message
::Raw(s
) => {
1074 let mut c
= Colorizer
::new(Stream
::Stderr
, cmd
.get_color());
1076 let mut message
= String
::new();
1077 std
::mem
::swap(s
, &mut message
);
1078 start_error(&mut c
);
1080 put_usage(&mut c
, usage
);
1081 try_help(&mut c
, get_help_flag(cmd
));
1082 *self = Self::Formatted(c
);
1084 Message
::Formatted(_
) => {}
1088 fn formatted(&self) -> Cow
<Colorizer
> {
1090 Message
::Raw(s
) => {
1091 let mut c
= Colorizer
::new(Stream
::Stderr
, ColorChoice
::Never
);
1092 start_error(&mut c
);
1096 Message
::Formatted(c
) => Cow
::Borrowed(c
),
1101 impl From
<String
> for Message
{
1102 fn from(inner
: String
) -> Self {
1107 impl From
<Colorizer
> for Message
{
1108 fn from(inner
: Colorizer
) -> Self {
1109 Self::Formatted(inner
)
1113 #[cfg(feature = "debug")]
1115 struct Backtrace(backtrace
::Backtrace
);
1117 #[cfg(feature = "debug")]
1119 fn new() -> Option
<Self> {
1120 Some(Self(backtrace
::Backtrace
::new()))
1124 #[cfg(feature = "debug")]
1125 impl Display
for Backtrace
{
1126 fn fmt(&self, f
: &mut Formatter
) -> fmt
::Result
{
1127 // `backtrace::Backtrace` uses `Debug` instead of `Display`
1128 write
!(f
, "{:?}", self.0)
1132 #[cfg(not(feature = "debug"))]
1136 #[cfg(not(feature = "debug"))]
1138 fn new() -> Option
<Self> {
1143 #[cfg(not(feature = "debug"))]
1144 impl Display
for Backtrace
{
1145 fn fmt(&self, _
: &mut Formatter
) -> fmt
::Result
{
1152 /// Check `clap::Error` impls Send and Sync.
1153 mod clap_error_impl_send_sync
{
1155 trait Foo
: std
::error
::Error
+ Send
+ Sync
+ '
static {}
1156 impl Foo
for Error {}