on master help sign in
Replace deprecated 'error-chain' with 'thiserror' (#1820)

We can't use #[from] on Error::Msg(String) because String does not implement Error. (Which it shouldn't; see e.g. https://internals.rust-lang.org/t/impl-error-for-string/8881.) So we implement From manually for Error::Msg, since our current code was written in that way for error-chain.

commit19c3e82abf70324dcf9d1c310aed7881f44fd35f authorMartin Nordholts <enselic@gmail.com> dateThu 26 Aug 2021, 13:12 (5 years ago) parentf1c0fd7
12 files changed+82−76
.github/workflows/CICD.yml+1−1 CHANGELOG.md+1 Cargo.lock+21−16 Cargo.toml+1−4 src/assets.rs+8−11 src/assets_metadata.rs+8−9 src/bin/bat/app.rs+1−1 src/bin/bat/main.rs−3 src/build_assets.rs+1−1 src/error.rs+36−26 src/output.rs+3−3 src/printer.rs+1−1
.github/workflows/CICD.yml+1−1
@@ -37,7 +37,7 @@ jobs:
3737 uses: actions-rs/cargo@v1
3838 with:
3939 command: clippy
40− args: --locked --all-targets --all-features
40+ args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
4141 - name: Run tests
4242 uses: actions-rs/cargo@v1
4343 with:
CHANGELOG.md+1
@@ -31,6 +31,7 @@
3131
3232- Deprecate `HighlightingAssets::syntaxes()` and `HighlightingAssets::syntax_for_file_name()`. Use `HighlightingAssets::get_syntaxes()` and `HighlightingAssets::get_syntax_for_file_name()` instead. They return a `Result` which is needed for upcoming lazy-loading work to improve startup performance. They also return what `SyntaxSet` the returned `SyntaxReference` belongs to. See #1747, #1755 and #1776 (@Enselic)
3333- Remove `HighlightingAssets::from_files` and `HighlightingAssets::save_to_cache`. Instead of calling the former and then the latter you now make a single call to `bat::assets::build`. See #1802 (@Enselic)
34+- Replace the `error::Error(error::ErrorKind, _)` struct and enum with an `error::Error` enum. `Error(ErrorKind::UnknownSyntax, _)` becomes `Error::UnknownSyntax`, etc. Also remove the `error::ResultExt` trait. These changes stem from replacing `error-chain` with `thiserror`. See #1820 (@Enselic)
3435
3536
3637
Cargo.lock+21−16
@@ -96,7 +96,6 @@ dependencies = [
9696 "content_inspector",
9797 "dirs-next",
9898 "encoding",
99− "error-chain",
10099 "git2",
101100 "globset",
102101 "grep-cli",
@@ -112,6 +111,7 @@ dependencies = [
112111 "shell-words",
113112 "syntect",
114113 "tempfile",
114+ "thiserror",
115115 "unicode-width",
116116 "wait-timeout",
117117 "wild",
@@ -376,15 +376,6 @@ version = "0.1.4"
376376source = "registry+https://github.com/rust-lang/crates.io-index"
377377checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
378378
379−[[package]]
380−name = "error-chain"
381−version = "0.12.4"
382−source = "registry+https://github.com/rust-lang/crates.io-index"
383−checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
384−dependencies = [
385− "version_check",
386−]
387−
388379[[package]]
389380name = "fancy-regex"
390381version = "0.7.1"
@@ -1188,6 +1179,26 @@ dependencies = [
11881179 "unicode-width",
11891180]
11901181
1182+[[package]]
1183+name = "thiserror"
1184+version = "1.0.26"
1185+source = "registry+https://github.com/rust-lang/crates.io-index"
1186+checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
1187+dependencies = [
1188+ "thiserror-impl",
1189+]
1190+
1191+[[package]]
1192+name = "thiserror-impl"
1193+version = "1.0.26"
1194+source = "registry+https://github.com/rust-lang/crates.io-index"
1195+checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
1196+dependencies = [
1197+ "proc-macro2",
1198+ "quote",
1199+ "syn",
1200+]
1201+
11911202[[package]]
11921203name = "tinyvec"
11931204version = "1.2.0"
@@ -1263,12 +1274,6 @@ version = "0.8.2"
12631274source = "registry+https://github.com/rust-lang/crates.io-index"
12641275checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
12651276
1266−[[package]]
1267−name = "version_check"
1268−version = "0.9.3"
1269−source = "registry+https://github.com/rust-lang/crates.io-index"
1270−checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
1271−
12721277[[package]]
12731278name = "wait-timeout"
12741279version = "0.2.0"
Cargo.toml+1−4
@@ -48,6 +48,7 @@ ansi_colours = "^1.0"
4848console = "0.14.1"
4949lazy_static = { version = "1.4", optional = true }
5050lazycell = "1.0"
51+thiserror = "1.0"
5152wild = { version = "2.0", optional = true }
5253content_inspector = "0.2.4"
5354encoding = "0.2"
@@ -79,10 +80,6 @@ optional = true
7980default-features = false
8081features = ["suggestions", "color", "wrap_help"]
8182
82−[dependencies.error-chain]
83−version = "0.12"
84−default-features = false
85−
8683[dev-dependencies]
8784assert_cmd = "1.0.8"
8885serial_test = "0.5.1"
src/assets.rs+8−11
@@ -163,7 +163,7 @@ impl HighlightingAssets {
163163 syntax_set
164164 .find_syntax_by_token(language)
165165 .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })
166− .ok_or_else(|| ErrorKind::UnknownSyntax(language.to_owned()).into())
166+ .ok_or_else(|| Error::UnknownSyntax(language.to_owned()))
167167 } else {
168168 let line_syntax = self.get_first_line_syntax(&mut input.reader)?;
169169
@@ -189,30 +189,27 @@ impl HighlightingAssets {
189189 .unwrap_or_else(|| path.to_owned());
190190
191191 match mapping.get_syntax_for(absolute_path) {
192− Some(MappingTarget::MapToUnknown) => line_syntax.ok_or_else(|| {
193− ErrorKind::UndetectedSyntax(path.to_string_lossy().into()).into()
194− }),
192+ Some(MappingTarget::MapToUnknown) => line_syntax
193+ .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())),
195194
196195 Some(MappingTarget::MapTo(syntax_name)) => {
197196 let syntax_set = self.get_syntax_set()?;
198197 syntax_set
199198 .find_syntax_by_name(syntax_name)
200199 .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })
201− .ok_or_else(|| ErrorKind::UnknownSyntax(syntax_name.to_owned()).into())
200+ .ok_or_else(|| Error::UnknownSyntax(syntax_name.to_owned()))
202201 }
203202
204203 None => {
205204 let file_name = path.file_name().unwrap_or_default();
206205 self.get_extension_syntax(file_name)?
207206 .or(line_syntax)
208− .ok_or_else(|| {
209− ErrorKind::UndetectedSyntax(path.to_string_lossy().into()).into()
210− })
207+ .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into()))
211208 }
212209 }
213210 } else {
214211 // If a path wasn't provided, we fall back to the detect first-line syntax.
215− line_syntax.ok_or_else(|| ErrorKind::UndetectedSyntax("[unknown]".into()).into())
212+ line_syntax.ok_or_else(|| Error::UndetectedSyntax("[unknown]".into()))
216213 }
217214 }
218215 }
@@ -314,14 +311,14 @@ pub(crate) fn get_integrated_themeset() -> ThemeSet {
314311}
315312
316313fn asset_from_cache<T: serde::de::DeserializeOwned>(path: &Path, description: &str) -> Result<T> {
317− let contents = fs::read(path).chain_err(|| {
314+ let contents = fs::read(path).map_err(|_| {
318315 format!(
319316 "Could not load cached {} '{}'",
320317 description,
321318 path.to_string_lossy()
322319 )
323320 })?;
324− from_reader(&contents[..]).chain_err(|| format!("Could not parse cached {}", description))
321+ from_reader(&contents[..]).map_err(|_| format!("Could not parse cached {}", description).into())
325322}
326323
327324#[cfg(test)]
src/assets_metadata.rs+8−9
@@ -52,16 +52,15 @@ impl AssetsMetadata {
5252 pub fn load_from_folder(path: &Path) -> Result<Option<Self>> {
5353 match Self::try_load_from_folder(path) {
5454 Ok(metadata) => Ok(Some(metadata)),
55− Err(e) => match e.kind() {
56− ErrorKind::SerdeYamlError(_) => Err(e),
57− _ => {
58− if path.join("syntaxes.bin").exists() || path.join("themes.bin").exists() {
59− Ok(Some(Self::default()))
60− } else {
61− Ok(None)
62− }
55+ Err(e) => {
56+ if let Error::SerdeYamlError(_) = e {
57+ Err(e)
58+ } else if path.join("syntaxes.bin").exists() || path.join("themes.bin").exists() {
59+ Ok(Some(Self::default()))
60+ } else {
61+ Ok(None)
6362 }
64− },
63+ }
6564 }
6665 }
6766
src/bin/bat/app.rs+1−1
@@ -62,7 +62,7 @@ impl App {
6262 // Read arguments from bats config file
6363 let mut args = get_args_from_env_var()
6464 .unwrap_or_else(get_args_from_config_file)
65− .chain_err(|| "Could not parse configuration file")?;
65+ .map_err(|_| "Could not parse configuration file")?;
6666
6767 // Put the zero-th CLI argument (program name) first
6868 args.insert(0, cli_args.next().unwrap());
src/bin/bat/main.rs−3
@@ -1,6 +1,3 @@
1−// `error_chain!` can recurse deeply
2−#![recursion_limit = "1024"]
3−
41mod app;
52mod assets;
63mod clap_app;
src/build_assets.rs+1−1
@@ -267,7 +267,7 @@ impl SyntaxSetDependencyBuilder {
267267
268268fn asset_to_cache<T: serde::Serialize>(asset: &T, path: &Path, description: &str) -> Result<()> {
269269 print!("Writing {} to {} ... ", description, path.to_string_lossy());
270− syntect::dumps::dump_to_file(asset, &path).chain_err(|| {
270+ syntect::dumps::dump_to_file(asset, &path).map_err(|_| {
271271 format!(
272272 "Could not save {} to {}",
273273 description,
src/error.rs+36−26
@@ -1,42 +1,52 @@
1−use error_chain::error_chain;
21use std::io::Write;
2+use thiserror::Error;
33
4−error_chain! {
5− foreign_links {
6− Clap(::clap::Error) #[cfg(feature = "minimal-application")];
7− Io(::std::io::Error);
8− SyntectError(::syntect::LoadingError);
9− ParseIntError(::std::num::ParseIntError);
10− GlobParsingError(::globset::Error);
11− SerdeYamlError(::serde_yaml::Error);
4+#[derive(Error, Debug)]
5+pub enum Error {
6+ #[error(transparent)]
7+ Io(#[from] ::std::io::Error),
8+ #[error(transparent)]
9+ SyntectError(#[from] ::syntect::LoadingError),
10+ #[error(transparent)]
11+ ParseIntError(#[from] ::std::num::ParseIntError),
12+ #[error(transparent)]
13+ GlobParsingError(#[from] ::globset::Error),
14+ #[error(transparent)]
15+ SerdeYamlError(#[from] ::serde_yaml::Error),
16+ #[error("unable to detect syntax for {0}")]
17+ UndetectedSyntax(String),
18+ #[error("unknown syntax: '{0}'")]
19+ UnknownSyntax(String),
20+ #[error("Unknown style '{0}'")]
21+ UnknownStyle(String),
22+ #[error("Use of bat as a pager is disallowed in order to avoid infinite recursion problems")]
23+ InvalidPagerValueBat,
24+ #[error("{0}")]
25+ Msg(String),
26+}
27+
28+impl From<&'static str> for Error {
29+ fn from(s: &'static str) -> Self {
30+ Error::Msg(s.to_owned())
1231 }
32+}
1333
14− errors {
15− UndetectedSyntax(input: String) {
16− description("unable to detect syntax"),
17− display("unable to detect syntax for {}", input)
18− }
19− UnknownSyntax(name: String) {
20− description("unknown syntax"),
21− display("unknown syntax: '{}'", name)
22− }
23− InvalidPagerValueBat {
24− description("invalid value `bat` for pager property"),
25− display("Use of bat as a pager is disallowed in order to avoid infinite recursion problems")
26− }
34+impl From<String> for Error {
35+ fn from(s: String) -> Self {
36+ Error::Msg(s)
2737 }
2838}
2939
40+pub type Result<T> = std::result::Result<T, Error>;
41+
3042pub fn default_error_handler(error: &Error, output: &mut dyn Write) {
3143 use ansi_term::Colour::Red;
3244
3345 match error {
34− Error(ErrorKind::Io(ref io_error), _)
35− if io_error.kind() == ::std::io::ErrorKind::BrokenPipe =>
36− {
46+ Error::Io(ref io_error) if io_error.kind() == ::std::io::ErrorKind::BrokenPipe => {
3747 ::std::process::exit(0);
3848 }
39− Error(ErrorKind::SerdeYamlError(_), _) => {
49+ Error::SerdeYamlError(_) => {
4050 writeln!(
4151 output,
4252 "{}: Error while parsing metadata.yaml file: {}",
src/output.rs+3−3
@@ -52,7 +52,7 @@ impl OutputType {
5252 use std::process::{Command, Stdio};
5353
5454 let pager_opt =
55− pager::get_pager(pager_from_config).chain_err(|| "Could not parse pager command.")?;
55+ pager::get_pager(pager_from_config).map_err(|_| "Could not parse pager command.")?;
5656
5757 let pager = match pager_opt {
5858 Some(pager) => pager,
@@ -60,7 +60,7 @@ impl OutputType {
6060 };
6161
6262 if pager.kind == PagerKind::Bat {
63− return Err(ErrorKind::InvalidPagerValueBat.into());
63+ return Err(Error::InvalidPagerValueBat);
6464 }
6565
6666 let resolved_path = match grep_cli::resolve_binary(&pager.bin) {
@@ -142,7 +142,7 @@ impl OutputType {
142142 OutputType::Pager(ref mut command) => command
143143 .stdin
144144 .as_mut()
145− .chain_err(|| "Could not open stdin for pager")?,
145+ .ok_or("Could not open stdin for pager")?,
146146 OutputType::Stdout(ref mut handle) => handle,
147147 })
148148 }
src/printer.rs+1−1
@@ -174,7 +174,7 @@ impl<'a> InteractivePrinter<'a> {
174174 let syntax_in_set =
175175 match assets.get_syntax(config.language, input, &config.syntax_mapping) {
176176 Ok(syntax_in_set) => syntax_in_set,
177− Err(Error(ErrorKind::UndetectedSyntax(_), _)) => {
177+ Err(Error::UndetectedSyntax(_)) => {
178178 let syntax_set = assets.get_syntax_set()?;
179179 let syntax = syntax_set.find_syntax_plain_text();
180180 SyntaxReferenceInSet { syntax, syntax_set }