summaryrefslogtreecommitdiffstats
path: root/src/err.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/err.rs')
-rw-r--r--src/err.rs250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/err.rs b/src/err.rs
new file mode 100644
index 00000000..26919593
--- /dev/null
+++ b/src/err.rs
@@ -0,0 +1,250 @@
+use std::io;
+use std::path::{Path, PathBuf};
+use std::result;
+
+use snafu::{Backtrace, Context, Snafu};
+
+pub type Result<T> = result::Result<T, Error>;
+
+#[derive(Debug, Snafu)]
+#[snafu(visibility(pub(crate)))]
+pub enum Error {
+ #[snafu(display("I/O error: {}", source))]
+ IO {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display(
+ "failed to retrieve current working directory: {}", source,
+ ))]
+ CurrentDir {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display("sorting by modified time is unsupported: {}", source))]
+ UnsupportedSortModified {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display("sorting by access time is unsupported: {}", source))]
+ UnsupportedSortAccess {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display("sorting by creation time is unsupported: {}", source))]
+ UnsupportedSortCreation {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display(
+ "I/O error parsing config in {}: {}",
+ path.display(),
+ source,
+ ))]
+ ConfigIO {
+ backtrace: Backtrace,
+ source: io::Error,
+ path: PathBuf,
+ },
+ #[snafu(display(
+ "config parse error on line {}: {}",
+ line_number,
+ source,
+ ))]
+ ConfigInvalidUTF8 {
+ backtrace: Backtrace,
+ source: bstr::Utf8Error,
+ line_number: u64,
+ },
+ #[snafu(display("failed to initialize logger: {}", source))]
+ LoggerInit {
+ backtrace: Backtrace,
+ source: log::SetLoggerError,
+ },
+ #[snafu(display("{}", source))]
+ Clap {
+ backtrace: Backtrace,
+ source: clap::Error,
+ },
+ #[snafu(display("{}", source))]
+ ReadManyPatterns {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[snafu(display("{}", source))]
+ ReadOSPattern {
+ backtrace: Backtrace,
+ source: grep::cli::InvalidPatternError,
+ },
+ #[snafu(display(
+ "A path separator must be exactly one byte, but \
+ the given separator is {} bytes: {}\n\
+ In some shells on Windows '/' is automatically \
+ expanded. Use '//' instead.",
+ separator.len(), grep::cli::escape(&separator),
+ ))]
+ InvalidPathSeparator {
+ backtrace: Backtrace,
+ separator: Vec<u8>,
+ },
+ #[snafu(display("error parsing -g/--glob: {}", source))]
+ InvalidGlobFlag {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error parsing --iglob: {}", source))]
+ InvalidIGlobFlag {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error building --glob matcher: {}", source))]
+ GlobBuild {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error parsing --pre-glob: {}", source))]
+ InvalidPreGlob {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error building --pre-glob matcher: {}", source))]
+ PreGlobBuild {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error parsing --type-add value: {}", source))]
+ InvalidTypeDefinition {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("error building type matcher: {}", source))]
+ TypeDefinitionBuild {
+ backtrace: Backtrace,
+ source: ignore::Error,
+ },
+ #[snafu(display("failed to parse {} value as a number: {}", flag, source))]
+ InvalidNumber {
+ backtrace: Backtrace,
+ source: std::num::ParseIntError,
+ flag: String,
+ },
+ #[snafu(display(
+ "failed to parse {} value as a file size: {}", flag, source,
+ ))]
+ InvalidHumanSize {
+ backtrace: Backtrace,
+ source: grep::cli::ParseSizeError,
+ flag: String,
+ },
+ #[snafu(display(
+ "number given to {} is too large (limit is {})",
+ flag, limit,
+ ))]
+ NumberTooBig {
+ backtrace: Backtrace,
+ flag: String,
+ limit: u64,
+ },
+ #[snafu(display("{}", source))]
+ SearchConfig {
+ backtrace: Backtrace,
+ source: grep::searcher::ConfigError,
+ },
+ #[snafu(display("invalid --colors spec: {}", source))]
+ InvalidColorSpec {
+ backtrace: Backtrace,
+ source: grep::printer::ColorError,
+ },
+ #[snafu(display("{}", suggest(source)))]
+ RustRegex {
+ backtrace: Backtrace,
+ source: grep::regex::Error,
+ },
+ #[snafu(display(
+ "regex could not be compiled with either the default regex \
+ engine or with PCRE2.\n\n\
+ default regex engine error:\n{}\n{}\n{}\n\n\
+ PCRE2 regex engine error:\n{}",
+ "~".repeat(79),
+ rust_err,
+ "~".repeat(79),
+ pcre_err,
+ ))]
+ Hybrid {
+ backtrace: Backtrace,
+ rust_err: Box<Error>,
+ pcre_err: Box<Error>,
+ },
+ #[snafu(display("failed to write type definitions to stdout: {}", source))]
+ WriteTypes {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+ #[cfg(feature = "pcre2")]
+ #[snafu(display("{}", suggest(source)))]
+ PCRE2Regex {
+ backtrace: Backtrace,
+ source: grep::pcre2::Error,
+ },
+ #[snafu(display("PCRE2 is not available in this build of ripgrep"))]
+ PCRE2Unavailable {
+ backtrace: Backtrace,
+ },
+ #[snafu(display("failed to write PCRE2 version to stdout: {}", source))]
+ PCRE2Version {
+ backtrace: Backtrace,
+ source: io::Error,
+ },
+}
+
+impl Error {
+ /// Return true if and only if this corresponds to an I/O error generated
+ /// by a broken pipe.
+ pub fn is_broken_pipe(&self) -> bool {
+ self.io_err().map_or(false, |e| e.kind() == io::ErrorKind::BrokenPipe)
+ }
+
+ /// Return a reference to this error's underlying I/O error, if one exists.
+ pub fn io_err(&self) -> Option<&io::Error> {
+ match *self {
+ Error::IO { ref source, .. } => Some(source),
+ Error::CurrentDir { ref source, .. } => Some(source),
+ Error::UnsupportedSortModified { ref source, .. } => Some(source),
+ Error::UnsupportedSortAccess { ref source, .. } => Some(source),
+ Error::UnsupportedSortCreation { ref source, .. } => Some(source),
+ Error::ConfigIO { ref source, .. } => Some(source),
+ Error::ReadManyPatterns { ref source, .. } => Some(source),
+ Error::WriteTypes { ref source, .. } => Some(source),
+ Error::PCRE2Version { ref source, .. } => Some(source),
+ _ => None,
+ }
+ }
+}
+
+/// Inspect an error's display string and look for potentially suggestions
+/// to give to an end user.
+///
+/// These include:
+///
+/// 1. If the error results from the use of a new line literal, then return a
+/// new message suggesting the use of the -U/--multiline flag.
+/// 2. If the error correspond to a syntax error that PCRE2 could handle, then
+/// add a message to suggest the use of -P/--pcre2.
+fn suggest<E: std::error::Error>(err: &E) -> String {
+ let msg = err.to_string();
+ if msg.contains("the literal") && msg.contains("not allowed") {
+ format!("{}
+
+Consider enabling multiline mode with the --multiline flag (or -U for short).
+When multiline mode is enabled, new line characters can be matched.", msg)
+ } else if cfg!(feature = "pcre2") &&
+ (msg.contains("backreferences") || msg.contains("look-around"))
+ {
+ format!("{}
+
+Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
+and look-around.", msg)
+ } else {
+ msg
+ }
+}