error.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. use std::ffi::OsString;
  2. use std::fmt;
  3. use std::num::ParseIntError;
  4. use crate::options::flags;
  5. use crate::options::parser::{Arg, Flag, ParseError};
  6. /// Something wrong with the combination of options the user has picked.
  7. #[derive(PartialEq, Eq, Debug)]
  8. pub enum OptionsError {
  9. /// There was an error (from `getopts`) parsing the arguments.
  10. Parse(ParseError),
  11. /// The user supplied an illegal choice to an Argument.
  12. BadArgument(&'static Arg, OsString),
  13. /// The user supplied a set of options that are unsupported
  14. Unsupported(String),
  15. /// An option was given twice or more in strict mode.
  16. Duplicate(Flag, Flag),
  17. /// Two options were given that conflict with one another.
  18. Conflict(&'static Arg, &'static Arg),
  19. /// An option was given that does nothing when another one either is or
  20. /// isn’t present.
  21. Useless(&'static Arg, bool, &'static Arg),
  22. /// An option was given that does nothing when either of two other options
  23. /// are not present.
  24. Useless2(&'static Arg, &'static Arg, &'static Arg),
  25. /// A very specific edge case where --tree can’t be used with --all twice.
  26. TreeAllAll,
  27. /// A numeric option was given that failed to be parsed as a number.
  28. FailedParse(String, NumberSource, ParseIntError),
  29. /// A glob ignore was given that failed to be parsed as a pattern.
  30. FailedGlobPattern(String),
  31. }
  32. /// The source of a string that failed to be parsed as a number.
  33. #[derive(PartialEq, Eq, Debug)]
  34. pub enum NumberSource {
  35. /// It came... from a command-line argument!
  36. Arg(&'static Arg),
  37. /// It came... from the environment!
  38. Env(&'static str),
  39. }
  40. impl From<glob::PatternError> for OptionsError {
  41. fn from(error: glob::PatternError) -> Self {
  42. Self::FailedGlobPattern(error.to_string())
  43. }
  44. }
  45. impl fmt::Display for NumberSource {
  46. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  47. match self {
  48. Self::Arg(arg) => write!(f, "option {arg}"),
  49. Self::Env(env) => write!(f, "environment variable {env}"),
  50. }
  51. }
  52. }
  53. impl fmt::Display for OptionsError {
  54. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  55. use crate::options::parser::TakesValue;
  56. #[rustfmt::skip]
  57. return match self {
  58. Self::BadArgument(arg, attempt) => {
  59. if let TakesValue::Necessary(Some(values)) = arg.takes_value {
  60. write!(
  61. f,
  62. "Option {} has no {:?} setting ({})",
  63. arg,
  64. attempt,
  65. Choices(values)
  66. )
  67. } else {
  68. write!(f, "Option {arg} has no {attempt:?} setting")
  69. }
  70. }
  71. Self::Parse(e) => write!(f, "{e}"),
  72. Self::Unsupported(e) => write!(f, "{e}"),
  73. Self::Conflict(a, b) => write!(f, "Option {a} conflicts with option {b}"),
  74. Self::Duplicate(a, b) if a == b => write!(f, "Flag {a} was given twice"),
  75. Self::Duplicate(a, b) => write!(f, "Flag {a} conflicts with flag {b}"),
  76. Self::Useless(a, false, b) => write!(f, "Option {a} is useless without option {b}"),
  77. Self::Useless(a, true, b) => write!(f, "Option {a} is useless given option {b}"),
  78. Self::Useless2(a, b1, b2) => write!(f, "Option {a} is useless without options {b1} or {b2}"),
  79. Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"),
  80. Self::FailedParse(s, n, e) => write!(f, "Value {s:?} not valid for {n}: {e}"),
  81. Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {e}"),
  82. };
  83. }
  84. }
  85. impl OptionsError {
  86. /// Try to second-guess what the user was trying to do, depending on what
  87. /// went wrong.
  88. pub fn suggestion(&self) -> Option<&'static str> {
  89. // ‘ls -lt’ and ‘ls -ltr’ are common combinations
  90. match self {
  91. Self::BadArgument(time, r) if *time == &flags::TIME && r == "r" => {
  92. Some("To sort oldest files last, try \"--sort oldest\", or just \"-sold\"")
  93. }
  94. Self::Parse(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') => {
  95. Some("To sort newest files last, try \"--sort newest\", or just \"-snew\"")
  96. }
  97. _ => None,
  98. }
  99. }
  100. }
  101. /// A list of legal choices for an argument-taking option.
  102. #[derive(PartialEq, Eq, Debug)]
  103. pub struct Choices(pub &'static [&'static str]);
  104. impl fmt::Display for Choices {
  105. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  106. write!(f, "choices: {}", self.0.join(", "))
  107. }
  108. }