summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMyriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com>2024-07-14 21:14:21 +0800
committerGitHub <noreply@github.com>2024-07-14 13:14:21 +0000
commita3f3a1a83330e3fe9a686fbe4c0eda9f1e9e99b2 (patch)
tree0c6b10649101d75573e453498901907bdec5a8b3
parent4d8976b619fbb2ab19c1e46fccbca4294c0c2d0b (diff)
Change the signature of `World::main` (#4531)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
-rw-r--r--crates/typst-cli/src/compile.rs67
-rw-r--r--crates/typst-cli/src/world.rs4
-rw-r--r--crates/typst-ide/src/lib.rs4
-rw-r--r--crates/typst-syntax/src/file.rs5
-rw-r--r--crates/typst-syntax/src/path.rs5
-rw-r--r--crates/typst/src/lib.rs65
-rw-r--r--docs/src/html.rs14
-rw-r--r--tests/fuzz/src/compile.rs16
-rw-r--r--tests/src/world.rs4
9 files changed, 97 insertions, 87 deletions
diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs
index 4b87c3bd..d1526425 100644
--- a/crates/typst-cli/src/compile.rs
+++ b/crates/typst-cli/src/compile.rs
@@ -5,16 +5,16 @@ use std::path::{Path, PathBuf};
use chrono::{Datelike, Timelike};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::term;
-use ecow::{eco_format, eco_vec, EcoString, EcoVec};
+use ecow::{eco_format, EcoString};
use parking_lot::RwLock;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
-use typst::diag::{bail, FileError, Severity, SourceDiagnostic, StrResult, Warned};
+use typst::diag::{bail, Severity, SourceDiagnostic, StrResult, Warned};
use typst::foundations::{Datetime, Smart};
use typst::layout::{Frame, PageRanges};
use typst::model::Document;
use typst::syntax::{FileId, Source, Span};
use typst::visualize::Color;
-use typst::{World, WorldExt};
+use typst::WorldExt;
use crate::args::{
CompileCommand, DiagnosticFormat, Input, Output, OutputFormat, PageRangeArgument,
@@ -96,21 +96,6 @@ pub fn compile_once(
Status::Compiling.print(command).unwrap();
}
- if let Err(errors) = world
- .source(world.main())
- .map_err(|err| hint_invalid_main_file(err, &command.common.input))
- {
- set_failed();
- if watching {
- Status::Error.print(command).unwrap();
- }
-
- print_diagnostics(world, &errors, &[], command.common.diagnostic_format)
- .map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
-
- return Ok(());
- }
-
let Warned { output, warnings } = typst::compile(world);
match output {
@@ -498,52 +483,6 @@ fn open_file(open: Option<&str>, path: &Path) -> StrResult<()> {
}
}
-/// Adds useful hints when the main source file couldn't be read
-/// and returns the final diagnostic.
-fn hint_invalid_main_file(
- file_error: FileError,
- input: &Input,
-) -> EcoVec<SourceDiagnostic> {
- let is_utf8_error = matches!(file_error, FileError::InvalidUtf8);
- let mut diagnostic =
- SourceDiagnostic::error(Span::detached(), EcoString::from(file_error));
-
- // Attempt to provide helpful hints for UTF-8 errors.
- // Perhaps the user mistyped the filename.
- // For example, they could have written "file.pdf" instead of
- // "file.typ".
- if is_utf8_error {
- if let Input::Path(path) = input {
- let extension = path.extension();
- if extension.is_some_and(|extension| extension == "typ") {
- // No hints if the file is already a .typ file.
- // The file is indeed just invalid.
- return eco_vec![diagnostic];
- }
-
- match extension {
- Some(extension) => {
- diagnostic.hint(eco_format!(
- "a file with the `.{}` extension is not usually a Typst file",
- extension.to_string_lossy()
- ));
- }
-
- None => {
- diagnostic
- .hint("a file without an extension is not usually a Typst file");
- }
- };
-
- if path.with_extension("typ").exists() {
- diagnostic.hint("check if you meant to use the `.typ` extension instead");
- }
- }
- }
-
- eco_vec![diagnostic]
-}
-
/// Print diagnostic messages to the terminal.
pub fn print_diagnostics(
world: &SystemWorld,
diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs
index 8e8b305f..5a0814a8 100644
--- a/crates/typst-cli/src/world.rs
+++ b/crates/typst-cli/src/world.rs
@@ -192,8 +192,8 @@ impl World for SystemWorld {
&self.book
}
- fn main(&self) -> Source {
- self.source(self.main).unwrap()
+ fn main(&self) -> FileId {
+ self.main
}
fn source(&self, id: FileId) -> FileResult<Source> {
diff --git a/crates/typst-ide/src/lib.rs b/crates/typst-ide/src/lib.rs
index c4a88085..403a36ba 100644
--- a/crates/typst-ide/src/lib.rs
+++ b/crates/typst-ide/src/lib.rs
@@ -139,8 +139,8 @@ mod tests {
&self.base.book
}
- fn main(&self) -> Source {
- self.main.clone()
+ fn main(&self) -> FileId {
+ self.main.id()
}
fn source(&self, id: FileId) -> FileResult<Source> {
diff --git a/crates/typst-syntax/src/file.rs b/crates/typst-syntax/src/file.rs
index 356337f3..89aaa55e 100644
--- a/crates/typst-syntax/src/file.rs
+++ b/crates/typst-syntax/src/file.rs
@@ -91,6 +91,11 @@ impl FileId {
Self::new(self.package().cloned(), self.vpath().join(path))
}
+ /// The same file location, but with a different extension.
+ pub fn with_extension(&self, extension: &str) -> Self {
+ Self::new(self.package().cloned(), self.vpath().with_extension(extension))
+ }
+
/// Construct from a raw number.
pub(crate) const fn from_raw(v: u16) -> Self {
Self(v)
diff --git a/crates/typst-syntax/src/path.rs b/crates/typst-syntax/src/path.rs
index b561128c..6c625642 100644
--- a/crates/typst-syntax/src/path.rs
+++ b/crates/typst-syntax/src/path.rs
@@ -85,6 +85,11 @@ impl VirtualPath {
Self::new(path)
}
}
+
+ /// The same path, but with a different extension.
+ pub fn with_extension(&self, extension: &str) -> Self {
+ Self(self.0.with_extension(extension))
+ }
}
impl Debug for VirtualPath {
diff --git a/crates/typst/src/lib.rs b/crates/typst/src/lib.rs
index 50575d12..cfcfd757 100644
--- a/crates/typst/src/lib.rs
+++ b/crates/typst/src/lib.rs
@@ -60,10 +60,12 @@ use std::collections::HashSet;
use std::ops::{Deref, Range};
use comemo::{Track, Tracked, Validate};
-use ecow::{EcoString, EcoVec};
+use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use typst_timing::{timed, TimingScope};
-use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult, Warned};
+use crate::diag::{
+ warning, FileError, FileResult, SourceDiagnostic, SourceResult, Warned,
+};
use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{
Array, Bytes, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
@@ -108,13 +110,19 @@ fn compile_inner(
let library = world.library();
let styles = StyleChain::new(&library.styles);
+ // Fetch the main source file once.
+ let main = world.main();
+ let main = world
+ .source(main)
+ .map_err(|err| hint_invalid_main_file(world, err, main))?;
+
// First evaluate the main source file into a module.
let content = crate::eval::eval(
world,
traced,
sink.track_mut(),
Route::default().track(),
- &world.main(),
+ &main,
)?
.content();
@@ -203,8 +211,8 @@ pub trait World: Send + Sync {
/// Metadata about all known fonts.
fn book(&self) -> &LazyHash<FontBook>;
- /// Access the main source file.
- fn main(&self) -> Source;
+ /// Get the file id of the main source file.
+ fn main(&self) -> FileId;
/// Try to access the specified source file.
fn source(&self, id: FileId) -> FileResult<Source>;
@@ -246,7 +254,7 @@ macro_rules! delegate_for_ptr {
self.deref().book()
}
- fn main(&self) -> Source {
+ fn main(&self) -> FileId {
self.deref().main()
}
@@ -402,3 +410,48 @@ fn prelude(global: &mut Scope) {
global.define("horizon", Alignment::HORIZON);
global.define("bottom", Alignment::BOTTOM);
}
+
+/// Adds useful hints when the main source file couldn't be read
+/// and returns the final diagnostic.
+fn hint_invalid_main_file(
+ world: Tracked<dyn World + '_>,
+ file_error: FileError,
+ input: FileId,
+) -> EcoVec<SourceDiagnostic> {
+ let is_utf8_error = matches!(file_error, FileError::InvalidUtf8);
+ let mut diagnostic =
+ SourceDiagnostic::error(Span::detached(), EcoString::from(file_error));
+
+ // Attempt to provide helpful hints for UTF-8 errors. Perhaps the user
+ // mistyped the filename. For example, they could have written "file.pdf"
+ // instead of "file.typ".
+ if is_utf8_error {
+ let path = input.vpath();
+ let extension = path.as_rootless_path().extension();
+ if extension.is_some_and(|extension| extension == "typ") {
+ // No hints if the file is already a .typ file.
+ // The file is indeed just invalid.
+ return eco_vec![diagnostic];
+ }
+
+ match extension {
+ Some(extension) => {
+ diagnostic.hint(eco_format!(
+ "a file with the `.{}` extension is not usually a Typst file",
+ extension.to_string_lossy()
+ ));
+ }
+
+ None => {
+ diagnostic
+ .hint("a file without an extension is not usually a Typst file");
+ }
+ };
+
+ if world.source(input.with_extension("typ")).is_ok() {
+ diagnostic.hint("check if you meant to use the `.typ` extension instead");
+ }
+ }
+
+ eco_vec![diagnostic]
+}
diff --git a/docs/src/html.rs b/docs/src/html.rs
index ab140a90..58c8e54c 100644
--- a/docs/src/html.rs
+++ b/docs/src/html.rs
@@ -6,7 +6,7 @@ use heck::{ToKebabCase, ToTitleCase};
use pulldown_cmark as md;
use serde::{Deserialize, Serialize};
use typed_arena::Arena;
-use typst::diag::{FileResult, StrResult};
+use typst::diag::{FileError, FileResult, StrResult};
use typst::foundations::{Bytes, Datetime};
use typst::layout::{Abs, Point, Size};
use typst::syntax::{FileId, Source, VirtualPath};
@@ -463,12 +463,16 @@ impl World for DocWorld {
&FONTS.0
}
- fn main(&self) -> Source {
- self.0.clone()
+ fn main(&self) -> FileId {
+ self.0.id()
}
- fn source(&self, _: FileId) -> FileResult<Source> {
- Ok(self.0.clone())
+ fn source(&self, id: FileId) -> FileResult<Source> {
+ if id == self.0.id() {
+ Ok(self.0.clone())
+ } else {
+ Err(FileError::NotFound(id.vpath().as_rootless_path().into()))
+ }
}
fn file(&self, id: FileId) -> FileResult<Bytes> {
diff --git a/tests/fuzz/src/compile.rs b/tests/fuzz/src/compile.rs
index 98c300ce..c9536150 100644
--- a/tests/fuzz/src/compile.rs
+++ b/tests/fuzz/src/compile.rs
@@ -39,16 +39,20 @@ impl World for FuzzWorld {
&self.book
}
- fn main(&self) -> Source {
- self.source.clone()
+ fn main(&self) -> FileId {
+ self.source.id()
}
- fn source(&self, src: FileId) -> FileResult<Source> {
- Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
+ fn source(&self, id: FileId) -> FileResult<Source> {
+ if id == self.source.id() {
+ Ok(self.source.clone())
+ } else {
+ Err(FileError::NotFound(id.vpath().as_rootless_path().into()))
+ }
}
- fn file(&self, src: FileId) -> FileResult<Bytes> {
- Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
+ fn file(&self, id: FileId) -> FileResult<Bytes> {
+ Err(FileError::NotFound(id.vpath().as_rootless_path().into()))
}
fn font(&self, _: usize) -> Option<Font> {
diff --git a/tests/src/world.rs b/tests/src/world.rs
index ad925a53..47b77d7e 100644
--- a/tests/src/world.rs
+++ b/tests/src/world.rs
@@ -43,8 +43,8 @@ impl World for TestWorld {
&self.base.book
}
- fn main(&self) -> Source {
- self.main.clone()
+ fn main(&self) -> FileId {
+ self.main.id()
}
fn source(&self, id: FileId) -> FileResult<Source> {