Forward third-party errors
Better to know something even if it isn't always formatted in the prettiest way
This commit is contained in:
parent
6483d3035b
commit
921b40cf9c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2925,6 +2925,7 @@ dependencies = [
|
||||
"codespan-reporting",
|
||||
"comemo",
|
||||
"dirs",
|
||||
"ecow",
|
||||
"env_proxy",
|
||||
"flate2",
|
||||
"inferno",
|
||||
|
@ -26,6 +26,7 @@ chrono = { version = "0.4.24", default-features = false, features = ["clock", "s
|
||||
clap = { version = "4.2.4", features = ["derive", "env"] }
|
||||
codespan-reporting = "0.11"
|
||||
comemo = "0.3"
|
||||
ecow = "0.1.1"
|
||||
dirs = "5"
|
||||
flate2 = "1"
|
||||
inferno = "0.11.15"
|
||||
|
@ -93,7 +93,7 @@ pub fn compile_once(
|
||||
}
|
||||
|
||||
print_diagnostics(world, &[], &warnings, command.common.diagnostic_format)
|
||||
.map_err(|_| "failed to print diagnostics")?;
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
|
||||
if let Some(open) = command.open.take() {
|
||||
open_file(open.as_deref(), &command.output())?;
|
||||
@ -115,7 +115,7 @@ pub fn compile_once(
|
||||
&warnings,
|
||||
command.common.diagnostic_format,
|
||||
)
|
||||
.map_err(|_| "failed to print diagnostics")?;
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,8 @@ fn export(document: &Document, command: &CompileCommand) -> StrResult<()> {
|
||||
fn export_pdf(document: &Document, command: &CompileCommand) -> StrResult<()> {
|
||||
let output = command.output();
|
||||
let buffer = typst::export::pdf(document);
|
||||
fs::write(output, buffer).map_err(|_| "failed to write PDF file")?;
|
||||
fs::write(output, buffer)
|
||||
.map_err(|err| eco_format!("failed to write PDF file ({err})"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -176,11 +177,14 @@ fn export_image(
|
||||
ImageExportFormat::Png => {
|
||||
let pixmap =
|
||||
typst::export::render(frame, command.ppi / 72.0, Color::WHITE);
|
||||
pixmap.save_png(path).map_err(|_| "failed to write PNG file")?;
|
||||
pixmap
|
||||
.save_png(path)
|
||||
.map_err(|err| eco_format!("failed to write PNG file ({err})"))?;
|
||||
}
|
||||
ImageExportFormat::Svg => {
|
||||
let svg = typst::export::svg(frame);
|
||||
fs::write(path, svg).map_err(|_| "failed to write SVG file")?;
|
||||
fs::write(path, svg)
|
||||
.map_err(|err| eco_format!("failed to write SVG file ({err})"))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ fn main() -> ExitCode {
|
||||
let _guard = match crate::tracing::setup_tracing(&ARGS) {
|
||||
Ok(guard) => guard,
|
||||
Err(err) => {
|
||||
eprintln!("failed to initialize tracing {}", err);
|
||||
eprintln!("failed to initialize tracing ({err})");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use codespan_reporting::term::{self, termcolor};
|
||||
use ecow::eco_format;
|
||||
use termcolor::WriteColor;
|
||||
use typst::diag::{PackageError, PackageResult};
|
||||
use typst::syntax::PackageSpec;
|
||||
@ -50,18 +51,19 @@ fn download_package(spec: &PackageSpec, package_dir: &Path) -> PackageResult<()>
|
||||
);
|
||||
|
||||
print_downloading(spec).unwrap();
|
||||
|
||||
let data = match download_with_progress(&url) {
|
||||
Ok(data) => data,
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
return Err(PackageError::NotFound(spec.clone()))
|
||||
}
|
||||
Err(_) => return Err(PackageError::NetworkFailed),
|
||||
Err(err) => return Err(PackageError::NetworkFailed(Some(eco_format!("{err}")))),
|
||||
};
|
||||
|
||||
let decompressed = flate2::read::GzDecoder::new(data.as_slice());
|
||||
tar::Archive::new(decompressed).unpack(package_dir).map_err(|_| {
|
||||
tar::Archive::new(decompressed).unpack(package_dir).map_err(|err| {
|
||||
fs::remove_dir_all(package_dir).ok();
|
||||
PackageError::MalformedArchive
|
||||
PackageError::MalformedArchive(Some(eco_format!("{err}")))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ pub fn query(command: &QueryCommand) -> StrResult<()> {
|
||||
let serialized = format(data, command)?;
|
||||
println!("{serialized}");
|
||||
print_diagnostics(&world, &[], &warnings, command.common.diagnostic_format)
|
||||
.map_err(|_| "failed to print diagnostics")?;
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
}
|
||||
|
||||
// Print diagnostics.
|
||||
@ -43,7 +43,7 @@ pub fn query(command: &QueryCommand) -> StrResult<()> {
|
||||
&warnings,
|
||||
command.common.diagnostic_format,
|
||||
)
|
||||
.map_err(|_| "failed to print diagnostics")?;
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,10 +128,10 @@ impl TracingGuard {
|
||||
impl Drop for TracingGuard {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
if let Err(e) = self.finish() {
|
||||
if let Err(err) = self.finish() {
|
||||
// Since we are finished, we cannot rely on tracing to log the
|
||||
// error.
|
||||
eprintln!("failed to flush tracing flamegraph: {e}");
|
||||
eprintln!("failed to flush tracing flamegraph ({err})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,15 +51,15 @@ pub fn update(command: &UpdateCommand) -> StrResult<()> {
|
||||
|
||||
return self_replace::self_replace(&backup_path)
|
||||
.and_then(|_| fs::remove_file(&backup_path))
|
||||
.map_err(|err| eco_format!("failed to revert to backup: {err}"));
|
||||
.map_err(|err| eco_format!("failed to revert to backup ({err})"));
|
||||
}
|
||||
|
||||
let current_exe = env::current_exe().map_err(|err| {
|
||||
eco_format!("failed to locate path of the running executable: {err}")
|
||||
eco_format!("failed to locate path of the running executable ({err})")
|
||||
})?;
|
||||
|
||||
fs::copy(current_exe, &backup_path)
|
||||
.map_err(|err| eco_format!("failed to create backup: {err}"))?;
|
||||
.map_err(|err| eco_format!("failed to create backup ({err})"))?;
|
||||
|
||||
let release = Release::from_tag(command.version.as_ref())?;
|
||||
if !update_needed(&release)? && !command.force {
|
||||
@ -69,14 +69,14 @@ pub fn update(command: &UpdateCommand) -> StrResult<()> {
|
||||
|
||||
let binary_data = release.download_binary(needed_asset()?)?;
|
||||
let mut temp_exe = NamedTempFile::new()
|
||||
.map_err(|err| eco_format!("failed to create temporary file: {err}"))?;
|
||||
.map_err(|err| eco_format!("failed to create temporary file ({err})"))?;
|
||||
temp_exe
|
||||
.write_all(&binary_data)
|
||||
.map_err(|err| eco_format!("failed to write binary data: {err}"))?;
|
||||
.map_err(|err| eco_format!("failed to write binary data ({err})"))?;
|
||||
|
||||
self_replace::self_replace(&temp_exe).map_err(|err| {
|
||||
fs::remove_file(&temp_exe).ok();
|
||||
eco_format!("failed to self-replace running executable: {err}")
|
||||
eco_format!("failed to self-replace running executable ({err})")
|
||||
})
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ impl Release {
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
bail!("release not found (searched at {url})")
|
||||
}
|
||||
Err(_) => bail!("failed to download release (network failed)"),
|
||||
Err(err) => bail!("failed to download release ({err})"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ impl Release {
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
bail!("asset not found (searched for {})", asset.name);
|
||||
}
|
||||
Err(_) => bail!("failed to load asset (network failed)"),
|
||||
Err(err) => bail!("failed to download asset ({err})"),
|
||||
};
|
||||
|
||||
if asset_name.contains("windows") {
|
||||
@ -152,7 +152,7 @@ impl Release {
|
||||
/// Extract the Typst binary from a ZIP archive.
|
||||
fn extract_binary_from_zip(data: &[u8], asset_name: &str) -> StrResult<Vec<u8>> {
|
||||
let mut archive = ZipArchive::new(Cursor::new(data))
|
||||
.map_err(|err| eco_format!("failed to extract ZIP archive: {err}"))?;
|
||||
.map_err(|err| eco_format!("failed to extract ZIP archive ({err})"))?;
|
||||
|
||||
let mut file = archive
|
||||
.by_name(&format!("{asset_name}/typst.exe"))
|
||||
@ -160,7 +160,7 @@ fn extract_binary_from_zip(data: &[u8], asset_name: &str) -> StrResult<Vec<u8>>
|
||||
|
||||
let mut buffer = vec![];
|
||||
file.read_to_end(&mut buffer).map_err(|err| {
|
||||
eco_format!("failed to read binary data from ZIP archive: {err}")
|
||||
eco_format!("failed to read binary data from ZIP archive ({err})")
|
||||
})?;
|
||||
|
||||
Ok(buffer)
|
||||
@ -172,14 +172,14 @@ fn extract_binary_from_tar_xz(data: &[u8]) -> StrResult<Vec<u8>> {
|
||||
|
||||
let mut file = archive
|
||||
.entries()
|
||||
.map_err(|err| eco_format!("failed to extract tar.xz archive: {err}"))?
|
||||
.map_err(|err| eco_format!("failed to extract tar.xz archive ({err})"))?
|
||||
.filter_map(Result::ok)
|
||||
.find(|e| e.path().unwrap_or_default().ends_with("typst"))
|
||||
.ok_or("tar.xz archive did not contain Typst binary")?;
|
||||
|
||||
let mut buffer = vec![];
|
||||
file.read_to_end(&mut buffer).map_err(|err| {
|
||||
eco_format!("failed to read binary data from tar.xz archive: {err}")
|
||||
eco_format!("failed to read binary data from tar.xz archive ({err})")
|
||||
})?;
|
||||
|
||||
Ok(buffer)
|
||||
@ -235,7 +235,7 @@ fn backup_path() -> StrResult<PathBuf> {
|
||||
let backup_dir = root_backup_dir.join("typst");
|
||||
|
||||
fs::create_dir_all(&backup_dir)
|
||||
.map_err(|err| eco_format!("failed to create backup directory: {err}"))?;
|
||||
.map_err(|err| eco_format!("failed to create backup directory ({err})"))?;
|
||||
|
||||
Ok(backup_dir.join("typst_backup.part"))
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> {
|
||||
// Setup file watching.
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut watcher = RecommendedWatcher::new(tx, notify::Config::default())
|
||||
.map_err(|_| "failed to setup file watching")?;
|
||||
.map_err(|err| eco_format!("failed to setup file watching ({err})"))?;
|
||||
|
||||
// Watch all the files that are used by the input file and its dependencies.
|
||||
watch_dependencies(&mut world, &mut watcher, HashSet::new())?;
|
||||
@ -41,7 +41,8 @@ pub fn watch(mut command: CompileCommand) -> StrResult<()> {
|
||||
.into_iter()
|
||||
.chain(std::iter::from_fn(|| rx.recv_timeout(timeout).ok()))
|
||||
{
|
||||
let event = event.map_err(|_| "failed to watch directory")?;
|
||||
let event =
|
||||
event.map_err(|err| eco_format!("failed to watch directory ({err})"))?;
|
||||
|
||||
// Workaround for notify-rs' implicit unwatch on remove/rename
|
||||
// (triggered by some editors when saving files) with the inotify
|
||||
@ -94,7 +95,7 @@ fn watch_dependencies(
|
||||
tracing::info!("Watching {}", path.display());
|
||||
watcher
|
||||
.watch(path, RecursiveMode::NonRecursive)
|
||||
.map_err(|_| eco_format!("failed to watch {path:?}"))?;
|
||||
.map_err(|err| eco_format!("failed to watch {path:?} ({err})"))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use typst::diag::{format_xml_like_error, FileError};
|
||||
use typst::eval::Bytes;
|
||||
use typst::syntax::is_newline;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -197,15 +198,16 @@ cast! {
|
||||
}
|
||||
|
||||
/// Format the user-facing CSV error message.
|
||||
fn format_csv_error(error: csv::Error, line: usize) -> EcoString {
|
||||
match error.kind() {
|
||||
fn format_csv_error(err: csv::Error, line: usize) -> EcoString {
|
||||
match err.kind() {
|
||||
csv::ErrorKind::Utf8 { .. } => "file is not valid utf-8".into(),
|
||||
csv::ErrorKind::UnequalLengths { expected_len, len, .. } => {
|
||||
eco_format!(
|
||||
"failed to parse csv file: found {len} instead of {expected_len} fields in line {line}"
|
||||
"failed to parse CSV (found {len} instead of \
|
||||
{expected_len} fields in line {line})"
|
||||
)
|
||||
}
|
||||
_ => "failed to parse csv file".into(),
|
||||
_ => eco_format!("failed to parse CSV ({err})"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,7 +280,7 @@ pub fn json_decode(
|
||||
) -> SourceResult<Value> {
|
||||
let Spanned { v: data, span } = data;
|
||||
serde_json::from_slice(data.as_slice())
|
||||
.map_err(format_json_error)
|
||||
.map_err(|err| eco_format!("failed to parse JSON ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
@ -302,16 +304,10 @@ pub fn json_encode(
|
||||
serde_json::to_string(&value)
|
||||
}
|
||||
.map(|v| v.into())
|
||||
.map_err(|e| eco_format!("failed to encode value as json: {e}"))
|
||||
.map_err(|err| eco_format!("failed to encode value as JSON ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
/// Format the user-facing JSON error message.
|
||||
fn format_json_error(error: serde_json::Error) -> EcoString {
|
||||
assert!(error.is_syntax() || error.is_eof());
|
||||
eco_format!("failed to parse json file: syntax error in line {}", error.line())
|
||||
}
|
||||
|
||||
/// Reads structured data from a TOML file.
|
||||
///
|
||||
/// The file must contain a valid TOML table. TOML tables will be converted into
|
||||
@ -366,7 +362,9 @@ pub fn toml_decode(
|
||||
let raw = std::str::from_utf8(data.as_slice())
|
||||
.map_err(|_| "file is not valid utf-8")
|
||||
.at(span)?;
|
||||
toml::from_str(raw).map_err(format_toml_error).at(span)
|
||||
toml::from_str(raw)
|
||||
.map_err(|err| format_toml_error(err, raw))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
/// Encodes structured data into a TOML string.
|
||||
@ -385,21 +383,21 @@ pub fn toml_encode(
|
||||
let Spanned { v: value, span } = value;
|
||||
if pretty { toml::to_string_pretty(&value) } else { toml::to_string(&value) }
|
||||
.map(|v| v.into())
|
||||
.map_err(|e| eco_format!("failed to encode value as toml: {e}"))
|
||||
.map_err(|err| eco_format!("failed to encode value as TOML ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
/// Format the user-facing TOML error message.
|
||||
fn format_toml_error(error: toml::de::Error) -> EcoString {
|
||||
if let Some(range) = error.span() {
|
||||
fn format_toml_error(error: toml::de::Error, raw: &str) -> EcoString {
|
||||
if let Some(head) = error.span().and_then(|range| raw.get(..range.start)) {
|
||||
let line = head.lines().count();
|
||||
let column = 1 + head.chars().rev().take_while(|&c| !is_newline(c)).count();
|
||||
eco_format!(
|
||||
"failed to parse toml file: {}, index {}-{}",
|
||||
"failed to parse TOML ({} at line {line} column {column})",
|
||||
error.message(),
|
||||
range.start,
|
||||
range.end
|
||||
)
|
||||
} else {
|
||||
eco_format!("failed to parse toml file: {}", error.message())
|
||||
eco_format!("failed to parse TOML ({})", error.message())
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,7 +462,7 @@ pub fn yaml_decode(
|
||||
) -> SourceResult<Value> {
|
||||
let Spanned { v: data, span } = data;
|
||||
serde_yaml::from_slice(data.as_slice())
|
||||
.map_err(format_yaml_error)
|
||||
.map_err(|err| eco_format!("failed to parse YAML ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
@ -480,15 +478,10 @@ pub fn yaml_encode(
|
||||
let Spanned { v: value, span } = value;
|
||||
serde_yaml::to_string(&value)
|
||||
.map(|v| v.into())
|
||||
.map_err(|e| eco_format!("failed to encode value as yaml: {e}"))
|
||||
.map_err(|err| eco_format!("failed to encode value as YAML ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
/// Format the user-facing YAML error message.
|
||||
fn format_yaml_error(error: serde_yaml::Error) -> EcoString {
|
||||
eco_format!("failed to parse yaml file: {}", error.to_string().trim())
|
||||
}
|
||||
|
||||
/// Reads structured data from a CBOR file.
|
||||
///
|
||||
/// The file must contain a valid cbor serialization. Mappings will be
|
||||
@ -529,7 +522,7 @@ pub fn cbor_decode(
|
||||
) -> SourceResult<Value> {
|
||||
let Spanned { v: data, span } = data;
|
||||
ciborium::from_reader(data.as_slice())
|
||||
.map_err(|e| eco_format!("failed to parse cbor: {e}"))
|
||||
.map_err(|err| eco_format!("failed to parse CBOR ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
@ -546,7 +539,7 @@ pub fn cbor_encode(
|
||||
let mut res = Vec::new();
|
||||
ciborium::into_writer(&value, &mut res)
|
||||
.map(|_| res.into())
|
||||
.map_err(|e| eco_format!("failed to encode value as cbor: {e}"))
|
||||
.map_err(|err| eco_format!("failed to encode value as CBOR ({err})"))
|
||||
.at(span)
|
||||
}
|
||||
|
||||
@ -661,5 +654,5 @@ fn convert_xml(node: roxmltree::Node) -> Value {
|
||||
|
||||
/// Format the user-facing XML error message.
|
||||
fn format_xml_error(error: roxmltree::Error) -> EcoString {
|
||||
format_xml_like_error("xml file", error)
|
||||
format_xml_like_error("XML", error)
|
||||
}
|
||||
|
@ -650,8 +650,8 @@ fn parse_bib(path_str: &str, src: &str) -> StrResult<Vec<hayagriva::Entry>> {
|
||||
}
|
||||
|
||||
/// Format a Hayagriva loading error.
|
||||
fn format_hayagriva_error(error: YamlBibliographyError) -> EcoString {
|
||||
eco_format!("{error}")
|
||||
fn format_hayagriva_error(err: YamlBibliographyError) -> EcoString {
|
||||
eco_format!("{err}")
|
||||
}
|
||||
|
||||
/// Format a BibLaTeX loading error.
|
||||
|
@ -485,10 +485,9 @@ fn load_syntaxes(paths: &SyntaxPaths, bytes: &[Bytes]) -> StrResult<Arc<SyntaxSe
|
||||
// We might have multiple sublime-syntax/yaml files
|
||||
for (path, bytes) in paths.0.iter().zip(bytes.iter()) {
|
||||
let src = std::str::from_utf8(bytes).map_err(FileError::from)?;
|
||||
out.add(
|
||||
SyntaxDefinition::load_from_str(src, false, None)
|
||||
.map_err(|e| eco_format!("failed to parse syntax file `{path}`: {e}"))?,
|
||||
);
|
||||
out.add(SyntaxDefinition::load_from_str(src, false, None).map_err(|err| {
|
||||
eco_format!("failed to parse syntax file `{path}` ({err})")
|
||||
})?);
|
||||
}
|
||||
|
||||
Ok(Arc::new(out.build()))
|
||||
@ -528,7 +527,7 @@ fn load_theme(path: EcoString, bytes: Bytes) -> StrResult<Arc<synt::Theme>> {
|
||||
|
||||
synt::ThemeSet::load_from_reader(&mut cursor)
|
||||
.map(Arc::new)
|
||||
.map_err(|e| eco_format!("failed to parse theme file `{path}`: {e}"))
|
||||
.map_err(|err| eco_format!("failed to parse theme file `{path}` ({err})"))
|
||||
}
|
||||
|
||||
/// Function to parse the theme argument.
|
||||
|
@ -320,21 +320,23 @@ pub enum FileError {
|
||||
/// The package the file is part of could not be loaded.
|
||||
Package(PackageError),
|
||||
/// Another error.
|
||||
Other,
|
||||
///
|
||||
/// The optional string can give more details, if available.
|
||||
Other(Option<EcoString>),
|
||||
}
|
||||
|
||||
impl FileError {
|
||||
/// Create a file error from an I/O error.
|
||||
pub fn from_io(error: io::Error, path: &Path) -> Self {
|
||||
match error.kind() {
|
||||
pub fn from_io(err: io::Error, path: &Path) -> Self {
|
||||
match err.kind() {
|
||||
io::ErrorKind::NotFound => Self::NotFound(path.into()),
|
||||
io::ErrorKind::PermissionDenied => Self::AccessDenied,
|
||||
io::ErrorKind::InvalidData
|
||||
if error.to_string().contains("stream did not contain valid UTF-8") =>
|
||||
if err.to_string().contains("stream did not contain valid UTF-8") =>
|
||||
{
|
||||
Self::InvalidUtf8
|
||||
}
|
||||
_ => Self::Other,
|
||||
_ => Self::Other(Some(eco_format!("{err}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -352,7 +354,8 @@ impl Display for FileError {
|
||||
Self::NotSource => f.pad("not a typst source file"),
|
||||
Self::InvalidUtf8 => f.pad("file is not valid utf-8"),
|
||||
Self::Package(error) => error.fmt(f),
|
||||
Self::Other => f.pad("failed to load file"),
|
||||
Self::Other(Some(err)) => write!(f, "failed to load file ({err})"),
|
||||
Self::Other(None) => f.pad("failed to load file"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,14 +373,14 @@ impl From<FromUtf8Error> for FileError {
|
||||
}
|
||||
|
||||
impl From<PackageError> for FileError {
|
||||
fn from(error: PackageError) -> Self {
|
||||
Self::Package(error)
|
||||
fn from(err: PackageError) -> Self {
|
||||
Self::Package(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileError> for EcoString {
|
||||
fn from(error: FileError) -> Self {
|
||||
eco_format!("{error}")
|
||||
fn from(err: FileError) -> Self {
|
||||
eco_format!("{err}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,16 +388,18 @@ impl From<FileError> for EcoString {
|
||||
pub type PackageResult<T> = Result<T, PackageError>;
|
||||
|
||||
/// An error that occured while trying to load a package.
|
||||
///
|
||||
/// Some variants have an optional string can give more details, if available.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum PackageError {
|
||||
/// The specified package does not exist.
|
||||
NotFound(PackageSpec),
|
||||
/// Failed to retrieve the package through the network.
|
||||
NetworkFailed,
|
||||
NetworkFailed(Option<EcoString>),
|
||||
/// The package archive was malformed.
|
||||
MalformedArchive,
|
||||
MalformedArchive(Option<EcoString>),
|
||||
/// Another error.
|
||||
Other,
|
||||
Other(Option<EcoString>),
|
||||
}
|
||||
|
||||
impl std::error::Error for PackageError {}
|
||||
@ -405,16 +410,25 @@ impl Display for PackageError {
|
||||
Self::NotFound(spec) => {
|
||||
write!(f, "package not found (searched for {spec})",)
|
||||
}
|
||||
Self::NetworkFailed => f.pad("failed to load package (network failed)"),
|
||||
Self::MalformedArchive => f.pad("failed to load package (archive malformed)"),
|
||||
Self::Other => f.pad("failed to load package"),
|
||||
Self::NetworkFailed(Some(err)) => {
|
||||
write!(f, "failed to download package ({err})")
|
||||
}
|
||||
Self::NetworkFailed(None) => f.pad("failed to download package"),
|
||||
Self::MalformedArchive(Some(err)) => {
|
||||
write!(f, "failed to decompress package ({err})")
|
||||
}
|
||||
Self::MalformedArchive(None) => {
|
||||
f.pad("failed to decompress package (archive malformed)")
|
||||
}
|
||||
Self::Other(Some(err)) => write!(f, "failed to load package ({err})"),
|
||||
Self::Other(None) => f.pad("failed to load package"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PackageError> for EcoString {
|
||||
fn from(error: PackageError) -> Self {
|
||||
eco_format!("{error}")
|
||||
fn from(err: PackageError) -> Self {
|
||||
eco_format!("{err}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,26 +437,26 @@ pub fn format_xml_like_error(format: &str, error: roxmltree::Error) -> EcoString
|
||||
match error {
|
||||
roxmltree::Error::UnexpectedCloseTag { expected, actual, pos } => {
|
||||
eco_format!(
|
||||
"failed to parse {format}: found closing tag '{actual}' \
|
||||
instead of '{expected}' in line {}",
|
||||
"failed to parse {format} (found closing tag '{actual}' \
|
||||
instead of '{expected}' in line {})",
|
||||
pos.row
|
||||
)
|
||||
}
|
||||
roxmltree::Error::UnknownEntityReference(entity, pos) => {
|
||||
eco_format!(
|
||||
"failed to parse {format}: unknown entity '{entity}' in line {}",
|
||||
"failed to parse {format} (unknown entity '{entity}' in line {})",
|
||||
pos.row
|
||||
)
|
||||
}
|
||||
roxmltree::Error::DuplicatedAttribute(attr, pos) => {
|
||||
eco_format!(
|
||||
"failed to parse {format}: duplicate attribute '{attr}' in line {}",
|
||||
"failed to parse {format}: (duplicate attribute '{attr}' in line {})",
|
||||
pos.row
|
||||
)
|
||||
}
|
||||
roxmltree::Error::NoRootNode => {
|
||||
eco_format!("failed to parse {format}: missing root node")
|
||||
eco_format!("failed to parse {format} (missing root node)")
|
||||
}
|
||||
_ => eco_format!("failed to parse {format}"),
|
||||
err => eco_format!("failed to parse {format} ({err})"),
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +228,10 @@ impl Debug for Datetime {
|
||||
fn format_time_format_error(error: Format) -> EcoString {
|
||||
match error {
|
||||
Format::InvalidComponent(name) => eco_format!("invalid component '{}'", name),
|
||||
_ => "failed to format datetime in the requested format".into(),
|
||||
Format::InsufficientTypeInformation { .. } => {
|
||||
"failed to format datetime (insufficient information)".into()
|
||||
}
|
||||
err => eco_format!("failed to format datetime in the requested format ({err})"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +266,6 @@ fn format_time_invalid_format_description_error(
|
||||
InvalidFormatDescription::NotSupported { context, what, index, .. } => {
|
||||
eco_format!("{} is not supported in {} at index {}", what, context, index)
|
||||
}
|
||||
_ => "failed to parse datetime format".into(),
|
||||
err => eco_format!("failed to parse datetime format ({err})"),
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ impl Plugin {
|
||||
pub fn new(bytes: Bytes) -> StrResult<Self> {
|
||||
let engine = Engine::default();
|
||||
let module = Module::new(&engine, bytes.as_slice())
|
||||
.map_err(|err| format!("failed to load WebAssembly module: {err}"))?;
|
||||
.map_err(|err| format!("failed to load WebAssembly module ({err})"))?;
|
||||
|
||||
let mut linker = Linker::new(&engine);
|
||||
linker
|
||||
|
@ -8,7 +8,7 @@ use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use comemo::{Prehashed, Track, Tracked};
|
||||
use ecow::{EcoString, EcoVec};
|
||||
use ecow::{eco_format, EcoString, EcoVec};
|
||||
use image::codecs::gif::GifDecoder;
|
||||
use image::codecs::jpeg::JpegDecoder;
|
||||
use image::codecs::png::PngDecoder;
|
||||
@ -463,7 +463,7 @@ impl SvgFontLoader for PreparedLoader {
|
||||
fn format_image_error(error: image::ImageError) -> EcoString {
|
||||
match error {
|
||||
image::ImageError::Limits(_) => "file is too large".into(),
|
||||
_ => "failed to decode image".into(),
|
||||
err => eco_format!("failed to decode image ({err})"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,8 +474,8 @@ fn format_usvg_error(error: usvg::Error) -> EcoString {
|
||||
usvg::Error::MalformedGZip => "file is not compressed correctly".into(),
|
||||
usvg::Error::ElementsLimitReached => "file is too large".into(),
|
||||
usvg::Error::InvalidSize => {
|
||||
"failed to parse svg: width, height, or viewbox is invalid".into()
|
||||
"failed to parse SVG (width, height, or viewbox is invalid)".into()
|
||||
}
|
||||
usvg::Error::ParsingFailed(error) => format_xml_like_error("svg", error),
|
||||
usvg::Error::ParsingFailed(error) => format_xml_like_error("SVG", error),
|
||||
}
|
||||
}
|
||||
|
@ -221,5 +221,5 @@
|
||||
#datetime.today().display(" []")
|
||||
|
||||
---
|
||||
// Error: 26-36 failed to format datetime in the requested format
|
||||
// Error: 26-36 failed to format datetime (insufficient information)
|
||||
#datetime.today().display("[hour]")
|
||||
|
@ -27,7 +27,7 @@
|
||||
#csv("nope.csv")
|
||||
|
||||
---
|
||||
// Error: 6-22 failed to parse csv file: found 3 instead of 2 fields in line 3
|
||||
// Error: 6-22 failed to parse CSV (found 3 instead of 2 fields in line 3)
|
||||
#csv("/files/bad.csv")
|
||||
|
||||
---
|
||||
@ -38,7 +38,7 @@
|
||||
#test(data.at(2).weight, 150)
|
||||
|
||||
---
|
||||
// Error: 7-24 failed to parse json file: syntax error in line 3
|
||||
// Error: 7-24 failed to parse JSON (expected value at line 3 column 14)
|
||||
#json("/files/bad.json")
|
||||
|
||||
---
|
||||
@ -80,7 +80,7 @@
|
||||
))
|
||||
|
||||
---
|
||||
// Error: 7-24 failed to parse toml file: expected `.`, `=`, index 15-16
|
||||
// Error: 7-24 failed to parse TOML (expected `.`, `=` at line 1 column 16)
|
||||
#toml("/files/bad.toml")
|
||||
|
||||
---
|
||||
@ -98,7 +98,7 @@
|
||||
#test(data.at("1"), "ok")
|
||||
|
||||
---
|
||||
// Error: 7-24 failed to parse yaml file: while parsing a flow sequence, expected ',' or ']' at line 2 column 1
|
||||
// Error: 7-24 failed to parse YAML (while parsing a flow sequence, expected ',' or ']' at line 2 column 1)
|
||||
#yaml("/files/bad.yaml")
|
||||
|
||||
---
|
||||
@ -127,5 +127,5 @@
|
||||
),))
|
||||
|
||||
---
|
||||
// Error: 6-22 failed to parse xml file: found closing tag 'data' instead of 'hello' in line 3
|
||||
// Error: 6-22 failed to parse XML (found closing tag 'data' instead of 'hello' in line 3)
|
||||
#xml("/files/bad.xml")
|
||||
|
@ -58,7 +58,7 @@ A #box(image("/files/tiger.jpg", height: 1cm, width: 80%)) B
|
||||
#image("./image.typ")
|
||||
|
||||
---
|
||||
// Error: 2-25 failed to parse svg: found closing tag 'g' instead of 'style' in line 4
|
||||
// Error: 2-25 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4)
|
||||
#image("/files/bad.svg")
|
||||
|
||||
---
|
||||
@ -66,7 +66,7 @@ A #box(image("/files/tiger.jpg", height: 1cm, width: 80%)) B
|
||||
#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||
|
||||
---
|
||||
// Error: 2-168 failed to parse svg: missing root node
|
||||
// Error: 2-168 failed to parse SVG (missing root node)
|
||||
#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||
|
||||
---
|
||||
@ -78,5 +78,5 @@ A #box(image("/files/tiger.jpg", height: 1cm, width: 80%)) B
|
||||
#image.decode(read("/files/tiger.jpg", encoding: none), format: "jpg", width: 80%)
|
||||
|
||||
---
|
||||
// Error: 2-83 failed to decode image
|
||||
// Error: 2-83 failed to decode image (Format error decoding Png: Invalid PNG signature.)
|
||||
#image.decode(read("/files/tiger.jpg", encoding: none), format: "png", width: 80%)
|
||||
|
Loading…
x
Reference in New Issue
Block a user