From 1c0868324863d9a4c422001204889ae1c14d8b68 Mon Sep 17 00:00:00 2001 From: Tobias Schmitz Date: Tue, 20 May 2025 17:02:17 +0200 Subject: [PATCH] feat: print path of external file if it isn't valid utf-8 --- crates/typst-library/src/diag.rs | 35 +++++++++++++++++++++++--------- tests/suite/loading/read.typ | 2 +- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/crates/typst-library/src/diag.rs b/crates/typst-library/src/diag.rs index 124d717c2..9622524e3 100644 --- a/crates/typst-library/src/diag.rs +++ b/crates/typst-library/src/diag.rs @@ -653,7 +653,7 @@ impl Loaded { }; eco_vec![error] } - (_, Ok(lines)) => { + (LoadSource::Bytes, Ok(lines)) => { let error = if let Some(pair) = pos.line_col(&lines) { let (line, col) = pair.numbers(); error!(self.source.span, "{msg} ({error} at {line}:{col})") @@ -673,12 +673,27 @@ impl Loaded { msg: impl std::fmt::Display, error: impl std::fmt::Display, ) -> EcoVec { - let pos = pos.into(); - let error = if let Some(pair) = pos.try_line_col(&self.bytes) { - let (line, col) = pair.numbers(); - error!(self.source.span, "{msg} ({error} at {line}:{col})") - } else { - error!(self.source.span, "{msg} ({error})") + let line_col = pos.into().try_line_col(&self.bytes).map(|p| p.numbers()); + let error = match (self.source.v, line_col) { + (LoadSource::Path(file), _) => { + let path = if let Some(package) = file.package() { + format!("{package}{}", file.vpath().as_rooted_path().display()) + } else { + format!("{}", file.vpath().as_rootless_path().display()) + }; + + if let Some((line, col)) = line_col { + error!(self.source.span, "{msg} ({error} in {path}:{line}:{col})") + } else { + error!(self.source.span, "{msg} ({error} in {path})") + } + } + (LoadSource::Bytes, Some((line, col))) => { + error!(self.source.span, "{msg} ({error} at {line}:{col})") + } + (LoadSource::Bytes, None) => { + error!(self.source.span, "{msg} ({error})") + } }; eco_vec![error] } @@ -804,8 +819,8 @@ impl LineCol { /// Format a user-facing error message for an XML-like file format. pub fn format_xml_like_error(format: &str, error: roxmltree::Error) -> LoadError { let pos = LineCol::one_based(error.pos().row as usize, error.pos().col as usize); - let msg = eco_format!("failed to parse {format}"); - let err = match error { + let message = eco_format!("failed to parse {format}"); + let error = match error { roxmltree::Error::UnexpectedCloseTag(expected, actual, _) => { eco_format!("found closing tag '{actual}' instead of '{expected}'") } @@ -821,5 +836,5 @@ pub fn format_xml_like_error(format: &str, error: roxmltree::Error) -> LoadError err => eco_format!("{err}"), }; - LoadError::new(pos, msg, err) + LoadError { pos: pos.into(), message, error } } diff --git a/tests/suite/loading/read.typ b/tests/suite/loading/read.typ index 00e3a5e4a..57bfc1d5c 100644 --- a/tests/suite/loading/read.typ +++ b/tests/suite/loading/read.typ @@ -8,5 +8,5 @@ #let data = read("/assets/text/missing.txt") --- read-invalid-utf-8 --- -// Error: 18-40 failed to convert to string (file is not valid utf-8 at 1:1) +// Error: 18-40 failed to convert to string (file is not valid utf-8 in assets/text/bad.txt:1:1) #let data = read("/assets/text/bad.txt")