Unified file loading errors

This commit is contained in:
Laurenz 2022-06-14 20:07:27 +02:00
parent 0dacb2d151
commit 7fb19d5ef8
6 changed files with 49 additions and 42 deletions

View File

@ -1,6 +1,8 @@
//! Diagnostics.
use std::fmt::{self, Display, Formatter};
use std::io;
use std::path::Path;
use crate::syntax::{Span, Spanned};
use crate::Context;
@ -134,3 +136,13 @@ pub fn with_alternative(msg: String, alt: &str) -> String {
msg
}
}
/// Format a file loading failure.
pub fn failed_to_load(target: &str, path: &Path, error: io::Error) -> String {
match error.kind() {
io::ErrorKind::NotFound => {
format!("file not found (searched at {})", path.display())
}
_ => format!("failed to load {target} ({error})"),
}
}

View File

@ -967,12 +967,7 @@ impl Eval for IncludeExpr {
fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult<Module> {
// Load the source file.
let full = vm.locate(&path).at(span)?;
let id = vm.ctx.sources.load(&full).map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
error!(span, "file not found (searched at {})", full.display())
}
_ => error!(span, "failed to load source file ({})", err),
})?;
let id = vm.ctx.sources.load(&full).at(span)?;
// Prevent cyclic importing.
if vm.route.contains(&id) {

View File

@ -10,6 +10,7 @@ use std::sync::Arc;
use image::io::Reader as ImageReader;
use image::{DynamicImage, ImageFormat};
use crate::diag::{failed_to_load, StrResult};
use crate::loading::{FileHash, Loader};
/// A unique identifier for a loaded image.
@ -60,19 +61,24 @@ impl ImageStore {
/// Load and decode an image file from a path relative to the compilation
/// environment's root.
pub fn load(&mut self, path: &Path) -> io::Result<ImageId> {
let hash = self.loader.resolve(path)?;
Ok(*match self.files.entry(hash) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let buffer = self.loader.load(path)?;
let ext = path.extension().and_then(OsStr::to_str).unwrap_or_default();
let image = Image::parse(&buffer, ext)?;
let id = ImageId(self.images.len() as u32);
self.images.push(image);
entry.insert(id)
}
})
pub fn load(&mut self, path: &Path) -> StrResult<ImageId> {
let mut try_load = || -> io::Result<ImageId> {
let hash = self.loader.resolve(path)?;
Ok(*match self.files.entry(hash) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let buffer = self.loader.load(path)?;
let ext =
path.extension().and_then(OsStr::to_str).unwrap_or_default();
let image = Image::parse(&buffer, ext)?;
let id = ImageId(self.images.len() as u32);
self.images.push(image);
entry.insert(id)
}
})
};
try_load().map_err(|err| failed_to_load("image", path, err))
}
}

View File

@ -16,13 +16,7 @@ impl ImageNode {
args.expect::<Spanned<EcoString>>("path to image file")?;
let full = vm.locate(&path).at(span)?;
let id = vm.ctx.images.load(&full).map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
error!(span, "file not found (searched at {})", full.display())
}
_ => error!(span, "failed to load image ({})", err),
})?;
let id = vm.ctx.images.load(&full).at(span)?;
let width = args.named("width")?;
let height = args.named("height")?;

View File

@ -206,10 +206,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
let mut ctx = Context::new(Arc::new(loader), config.build());
// Load the source file.
let id = ctx
.sources
.load(&command.input)
.map_err(|_| "failed to load source file")?;
let id = ctx.sources.load(&command.input)?;
// Typeset.
match typst::typeset(&mut ctx, id) {

View File

@ -8,7 +8,7 @@ use std::sync::Arc;
use unscanny::Scanner;
use crate::diag::TypResult;
use crate::diag::{failed_to_load, StrResult, TypResult};
use crate::loading::{FileHash, Loader};
use crate::parse::{is_newline, parse, reparse};
use crate::syntax::ast::Markup;
@ -74,19 +74,22 @@ impl SourceStore {
///
/// If there already exists a source file for this path, it is
/// [replaced](SourceFile::replace).
pub fn load(&mut self, path: impl AsRef<Path>) -> io::Result<SourceId> {
let path = path.as_ref();
let hash = self.loader.resolve(path)?;
if let Some(&id) = self.files.get(&hash) {
return Ok(id);
}
pub fn load(&mut self, path: &Path) -> StrResult<SourceId> {
let mut try_load = || -> io::Result<SourceId> {
let hash = self.loader.resolve(path)?;
if let Some(&id) = self.files.get(&hash) {
return Ok(id);
}
let data = self.loader.load(path)?;
let src = String::from_utf8(data).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "file is not valid utf-8")
})?;
let data = self.loader.load(path)?;
let src = String::from_utf8(data).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "file is not valid utf-8")
})?;
Ok(self.provide(path, src))
Ok(self.provide(path, src))
};
try_load().map_err(|err| failed_to_load("source file", path, err))
}
/// Directly provide a source file.