cli: Use anyhow and thiserror for errors
This patch updates the CLI to use anyhow and thiserror for error management. The main feature that our custom `Error` type was providing was a _list_ of messages, which would allow us to annotate "lower-level" errors with more contextual information. This is exactly what's provided by anyhow's `Context` trait. (This is setup work for a future PR that will pull the `config` and `loader` modules out into separate crates; by using `anyhow` we wouldn't have to deal with a circular dependency between with the new crates.)
This commit is contained in:
parent
9d77561c43
commit
d2d01e77e3
33 changed files with 237 additions and 419 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use super::error::{Error, Result};
|
||||
use anyhow::{anyhow, Context, Error, Result};
|
||||
use libloading::{Library, Symbol};
|
||||
use once_cell::unsync::OnceCell;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
|
|
@ -162,7 +162,7 @@ impl Loader {
|
|||
// one to use by applying the configurations' content regexes.
|
||||
else {
|
||||
let file_contents = fs::read(path)
|
||||
.map_err(Error::wrap(|| format!("Failed to read path {:?}", path)))?;
|
||||
.with_context(|| format!("Failed to read path {:?}", path))?;
|
||||
let file_contents = String::from_utf8_lossy(&file_contents);
|
||||
let mut best_score = -2isize;
|
||||
let mut best_configuration_id = None;
|
||||
|
|
@ -250,9 +250,9 @@ impl Loader {
|
|||
name: String,
|
||||
}
|
||||
let mut grammar_file =
|
||||
fs::File::open(grammar_path).map_err(Error::wrap(|| "Failed to read grammar.json"))?;
|
||||
fs::File::open(grammar_path).with_context(|| "Failed to read grammar.json")?;
|
||||
let grammar_json: GrammarJSON = serde_json::from_reader(BufReader::new(&mut grammar_file))
|
||||
.map_err(Error::wrap(|| "Failed to parse grammar.json"))?;
|
||||
.with_context(|| "Failed to parse grammar.json")?;
|
||||
|
||||
let scanner_path = if scanner_path.exists() {
|
||||
Some(scanner_path)
|
||||
|
|
@ -283,9 +283,8 @@ impl Loader {
|
|||
let mut library_path = self.parser_lib_path.join(name);
|
||||
library_path.set_extension(DYLIB_EXTENSION);
|
||||
|
||||
let recompile = needs_recompile(&library_path, &parser_path, &scanner_path).map_err(
|
||||
Error::wrap(|| "Failed to compare source and binary timestamps"),
|
||||
)?;
|
||||
let recompile = needs_recompile(&library_path, &parser_path, &scanner_path)
|
||||
.with_context(|| "Failed to compare source and binary timestamps")?;
|
||||
|
||||
if recompile {
|
||||
let mut config = cc::Build::new();
|
||||
|
|
@ -336,26 +335,23 @@ impl Loader {
|
|||
|
||||
let output = command
|
||||
.output()
|
||||
.map_err(Error::wrap(|| "Failed to execute C compiler"))?;
|
||||
.with_context(|| "Failed to execute C compiler")?;
|
||||
if !output.status.success() {
|
||||
return Err(Error::new(format!(
|
||||
return Err(anyhow!(
|
||||
"Parser compilation failed.\nStdout: {}\nStderr: {}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
)));
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let library = unsafe { Library::new(&library_path) }.map_err(Error::wrap(|| {
|
||||
format!("Error opening dynamic library {:?}", &library_path)
|
||||
}))?;
|
||||
let library = unsafe { Library::new(&library_path) }
|
||||
.with_context(|| format!("Error opening dynamic library {:?}", &library_path))?;
|
||||
let language_fn_name = format!("tree_sitter_{}", replace_dashes_with_underscores(name));
|
||||
let language = unsafe {
|
||||
let language_fn: Symbol<unsafe extern "C" fn() -> Language> = library
|
||||
.get(language_fn_name.as_bytes())
|
||||
.map_err(Error::wrap(|| {
|
||||
format!("Failed to load symbol {}", language_fn_name)
|
||||
}))?;
|
||||
.with_context(|| format!("Failed to load symbol {}", language_fn_name))?;
|
||||
language_fn()
|
||||
};
|
||||
mem::forget(library);
|
||||
|
|
@ -370,8 +366,7 @@ impl Loader {
|
|||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to load language for injection string '{}': {}",
|
||||
string,
|
||||
e.message()
|
||||
string, e
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
@ -380,8 +375,7 @@ impl Loader {
|
|||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to load property sheet for injection string '{}': {}",
|
||||
string,
|
||||
e.message()
|
||||
string, e
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
@ -646,7 +640,7 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
ranges: &'b Vec<(String, Range<usize>)>,
|
||||
source: &str,
|
||||
start_offset: usize,
|
||||
) -> (&'b str, QueryError) {
|
||||
) -> Error {
|
||||
let offset_within_section = error.offset - start_offset;
|
||||
let (path, range) = ranges
|
||||
.iter()
|
||||
|
|
@ -657,7 +651,7 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
.chars()
|
||||
.filter(|c| *c == '\n')
|
||||
.count();
|
||||
(path.as_ref(), error)
|
||||
Error::from(error).context(format!("Error in query file {:?}", path))
|
||||
}
|
||||
|
||||
fn read_queries(
|
||||
|
|
@ -671,18 +665,16 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
for path in paths {
|
||||
let abs_path = self.root_path.join(path);
|
||||
let prev_query_len = query.len();
|
||||
query += &fs::read_to_string(&abs_path).map_err(Error::wrap(|| {
|
||||
format!("Failed to read query file {:?}", path)
|
||||
}))?;
|
||||
query += &fs::read_to_string(&abs_path)
|
||||
.with_context(|| format!("Failed to read query file {:?}", path))?;
|
||||
path_ranges.push((path.clone(), prev_query_len..query.len()));
|
||||
}
|
||||
} else {
|
||||
let queries_path = self.root_path.join("queries");
|
||||
let path = queries_path.join(default_path);
|
||||
if path.exists() {
|
||||
query = fs::read_to_string(&path).map_err(Error::wrap(|| {
|
||||
format!("Failed to read query file {:?}", path)
|
||||
}))?;
|
||||
query = fs::read_to_string(&path)
|
||||
.with_context(|| format!("Failed to read query file {:?}", path))?;
|
||||
path_ranges.push((default_path.to_string(), 0..query.len()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue