misfire.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. use std::ffi::OsString;
  2. use std::fmt;
  3. use std::num::ParseIntError;
  4. use glob;
  5. use options::{flags, HelpString, VersionString};
  6. use options::parser::{Arg, Flag, ParseError};
  7. /// A **misfire** is a thing that can happen instead of listing files -- a
  8. /// catch-all for anything outside the program’s normal execution.
  9. #[derive(PartialEq, Debug)]
  10. pub enum Misfire {
  11. /// The getopts crate didn’t like these Arguments.
  12. InvalidOptions(ParseError),
  13. /// The user supplied an illegal choice to an Argument.
  14. BadArgument(&'static Arg, OsString),
  15. /// The user asked for help. This isn’t strictly an error, which is why
  16. /// this enum isn’t named Error!
  17. Help(HelpString),
  18. /// The user wanted the version number.
  19. Version(VersionString),
  20. /// An option was given twice or more in strict mode.
  21. Duplicate(Flag, Flag),
  22. /// Two options were given that conflict with one another.
  23. Conflict(&'static Arg, &'static Arg),
  24. /// An option was given that does nothing when another one either is or
  25. /// isn't present.
  26. Useless(&'static Arg, bool, &'static Arg),
  27. /// An option was given that does nothing when either of two other options
  28. /// are not present.
  29. Useless2(&'static Arg, &'static Arg, &'static Arg),
  30. /// A very specific edge case where --tree can’t be used with --all twice.
  31. TreeAllAll,
  32. /// A numeric option was given that failed to be parsed as a number.
  33. FailedParse(ParseIntError),
  34. /// A glob ignore was given that failed to be parsed as a pattern.
  35. FailedGlobPattern(String),
  36. }
  37. impl Misfire {
  38. /// The OS return code this misfire should signify.
  39. pub fn is_error(&self) -> bool {
  40. match *self {
  41. Misfire::Help(_) => false,
  42. Misfire::Version(_) => false,
  43. _ => true,
  44. }
  45. }
  46. }
  47. impl From<glob::PatternError> for Misfire {
  48. fn from(error: glob::PatternError) -> Misfire {
  49. Misfire::FailedGlobPattern(error.to_string())
  50. }
  51. }
  52. impl fmt::Display for Misfire {
  53. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  54. use options::parser::TakesValue;
  55. use self::Misfire::*;
  56. match *self {
  57. BadArgument(ref arg, ref attempt) => {
  58. if let TakesValue::Necessary(Some(values)) = arg.takes_value {
  59. write!(f, "Option {} has no {:?} setting ({})", arg, attempt, Choices(values))
  60. }
  61. else {
  62. write!(f, "Option {} has no {:?} setting", arg, attempt)
  63. }
  64. },
  65. InvalidOptions(ref e) => write!(f, "{}", e),
  66. Help(ref text) => write!(f, "{}", text),
  67. Version(ref version) => write!(f, "{}", version),
  68. Conflict(ref a, ref b) => write!(f, "Option {} conflicts with option {}", a, b),
  69. Duplicate(ref a, ref b) => if a == b { write!(f, "Flag {} was given twice", a) }
  70. else { write!(f, "Flag {} conflicts with flag {}", a, b) },
  71. Useless(ref a, false, ref b) => write!(f, "Option {} is useless without option {}", a, b),
  72. Useless(ref a, true, ref b) => write!(f, "Option {} is useless given option {}", a, b),
  73. Useless2(ref a, ref b1, ref b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
  74. TreeAllAll => write!(f, "Option --tree is useless given --all --all"),
  75. FailedParse(ref e) => write!(f, "Failed to parse number: {}", e),
  76. FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e),
  77. }
  78. }
  79. }
  80. impl fmt::Display for ParseError {
  81. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  82. use self::ParseError::*;
  83. match *self {
  84. NeedsValue { ref flag, values: None } => write!(f, "Flag {} needs a value", flag),
  85. NeedsValue { ref flag, values: Some(cs) } => write!(f, "Flag {} needs a value ({})", flag, Choices(cs)),
  86. ForbiddenValue { ref flag } => write!(f, "Flag {} cannot take a value", flag),
  87. UnknownShortArgument { ref attempt } => write!(f, "Unknown argument -{}", *attempt as char),
  88. UnknownArgument { ref attempt } => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
  89. }
  90. }
  91. }
  92. impl Misfire {
  93. /// Try to second-guess what the user was trying to do, depending on what
  94. /// went wrong.
  95. pub fn suggestion(&self) -> Option<&'static str> {
  96. // ‘ls -lt’ and ‘ls -ltr’ are common combinations
  97. match *self {
  98. Misfire::BadArgument(ref time, ref r) if *time == &flags::TIME && r == "r" =>
  99. Some("To sort oldest files last, try \"--sort oldest\", or just \"-sold\""),
  100. Misfire::InvalidOptions(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') =>
  101. Some("To sort newest files last, try \"--sort newest\", or just \"-snew\""),
  102. _ => None
  103. }
  104. }
  105. }
  106. /// A list of legal choices for an argument-taking option.
  107. #[derive(PartialEq, Debug)]
  108. pub struct Choices(&'static [&'static str]);
  109. impl fmt::Display for Choices {
  110. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  111. write!(f, "choices: {}", self.0.join(", "))
  112. }
  113. }