summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-cli/src/compile.rs9
-rw-r--r--crates/typst-cli/src/query.rs10
-rw-r--r--crates/typst-ide/src/analyze.rs17
-rw-r--r--crates/typst-ide/src/complete.rs3
-rw-r--r--crates/typst-ide/src/jump.rs5
-rw-r--r--crates/typst-ide/src/tooltip.rs8
-rw-r--r--crates/typst/src/diag.rs9
-rw-r--r--crates/typst/src/engine.rs117
-rw-r--r--crates/typst/src/eval/call.rs10
-rw-r--r--crates/typst/src/eval/import.rs10
-rw-r--r--crates/typst/src/eval/markup.rs4
-rw-r--r--crates/typst/src/eval/mod.rs18
-rw-r--r--crates/typst/src/eval/tracer.rs82
-rw-r--r--crates/typst/src/eval/vm.rs4
-rw-r--r--crates/typst/src/foundations/func.rs3
-rw-r--r--crates/typst/src/introspection/counter.rs12
-rw-r--r--crates/typst/src/introspection/state.rs12
-rw-r--r--crates/typst/src/layout/inline/mod.rs12
-rw-r--r--crates/typst/src/layout/mod.rs21
-rw-r--r--crates/typst/src/lib.rs77
-rw-r--r--crates/typst/src/realize/process.rs2
-rw-r--r--crates/typst/src/text/mod.rs2
22 files changed, 246 insertions, 201 deletions
diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs
index 584ccc85..ae712a85 100644
--- a/crates/typst-cli/src/compile.rs
+++ b/crates/typst-cli/src/compile.rs
@@ -8,8 +8,7 @@ use codespan_reporting::term;
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use parking_lot::RwLock;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
-use typst::diag::{bail, FileError, Severity, SourceDiagnostic, StrResult};
-use typst::eval::Tracer;
+use typst::diag::{bail, FileError, Severity, SourceDiagnostic, StrResult, Warned};
use typst::foundations::{Datetime, Smart};
use typst::layout::{Frame, PageRanges};
use typst::model::Document;
@@ -112,11 +111,9 @@ pub fn compile_once(
return Ok(());
}
- let mut tracer = Tracer::new();
- let result = typst::compile(world, &mut tracer);
- let warnings = tracer.warnings();
+ let Warned { output, warnings } = typst::compile(world);
- match result {
+ match output {
// Export the PDF / PNG.
Ok(document) => {
export(world, &document, command, watching)?;
diff --git a/crates/typst-cli/src/query.rs b/crates/typst-cli/src/query.rs
index 2e8bf7f8..a8012777 100644
--- a/crates/typst-cli/src/query.rs
+++ b/crates/typst-cli/src/query.rs
@@ -1,8 +1,8 @@
use comemo::Track;
use ecow::{eco_format, EcoString};
use serde::Serialize;
-use typst::diag::{bail, HintedStrResult, StrResult};
-use typst::eval::{eval_string, EvalMode, Tracer};
+use typst::diag::{bail, HintedStrResult, StrResult, Warned};
+use typst::eval::{eval_string, EvalMode};
use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
use typst::model::Document;
use typst::syntax::Span;
@@ -21,11 +21,9 @@ pub fn query(command: &QueryCommand) -> HintedStrResult<()> {
world.reset();
world.source(world.main()).map_err(|err| err.to_string())?;
- let mut tracer = Tracer::new();
- let result = typst::compile(&world, &mut tracer);
- let warnings = tracer.warnings();
+ let Warned { output, warnings } = typst::compile(&world);
- match result {
+ match output {
// Retrieve and print query results.
Ok(document) => {
let data = retrieve(&world, command, &document)?;
diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs
index d27ce176..b43d87cd 100644
--- a/crates/typst-ide/src/analyze.rs
+++ b/crates/typst-ide/src/analyze.rs
@@ -1,7 +1,7 @@
use comemo::Track;
use ecow::{eco_vec, EcoString, EcoVec};
-use typst::engine::{Engine, Route};
-use typst::eval::{Tracer, Vm};
+use typst::engine::{Engine, Route, Sink, Traced};
+use typst::eval::Vm;
use typst::foundations::{Context, Label, Scopes, Styles, Value};
use typst::introspection::Introspector;
use typst::model::{BibliographyElem, Document};
@@ -38,10 +38,7 @@ pub fn analyze_expr(
}
}
- let mut tracer = Tracer::new();
- tracer.inspect(node.span());
- typst::compile(world, &mut tracer).ok();
- return tracer.values();
+ return typst::trace(world, node.span());
}
};
@@ -59,12 +56,14 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
}
let introspector = Introspector::default();
- let mut tracer = Tracer::new();
+ let traced = Traced::default();
+ let mut sink = Sink::new();
let engine = Engine {
world: world.track(),
- route: Route::default(),
introspector: introspector.track(),
- tracer: tracer.track_mut(),
+ traced: traced.track(),
+ sink: sink.track_mut(),
+ route: Route::default(),
};
let context = Context::none();
diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs
index 2c4680d1..608b1473 100644
--- a/crates/typst-ide/src/complete.rs
+++ b/crates/typst-ide/src/complete.rs
@@ -1406,7 +1406,6 @@ impl<'a> CompletionContext<'a> {
#[cfg(test)]
mod tests {
- use typst::eval::Tracer;
use super::autocomplete;
use crate::tests::TestWorld;
@@ -1414,7 +1413,7 @@ mod tests {
#[track_caller]
fn test(text: &str, cursor: usize, contains: &[&str], excludes: &[&str]) {
let world = TestWorld::new(text);
- let doc = typst::compile(&world, &mut Tracer::new()).ok();
+ let doc = typst::compile(&world).output.ok();
let (_, completions) =
autocomplete(&world, doc.as_ref(), &world.main, cursor, true)
.unwrap_or_default();
diff --git a/crates/typst-ide/src/jump.rs b/crates/typst-ide/src/jump.rs
index 3bcaa7a3..f632d933 100644
--- a/crates/typst-ide/src/jump.rs
+++ b/crates/typst-ide/src/jump.rs
@@ -170,7 +170,6 @@ fn is_in_rect(pos: Point, size: Size, click: Point) -> bool {
mod tests {
use std::num::NonZeroUsize;
- use typst::eval::Tracer;
use typst::layout::{Abs, Point, Position};
use super::{jump_from_click, jump_from_cursor, Jump};
@@ -200,14 +199,14 @@ mod tests {
#[track_caller]
fn test_click(text: &str, click: Point, expected: Option<Jump>) {
let world = TestWorld::new(text);
- let doc = typst::compile(&world, &mut Tracer::new()).unwrap();
+ let doc = typst::compile(&world).output.unwrap();
assert_eq!(jump_from_click(&world, &doc, &doc.pages[0].frame, click), expected);
}
#[track_caller]
fn test_cursor(text: &str, cursor: usize, expected: Option<Position>) {
let world = TestWorld::new(text);
- let doc = typst::compile(&world, &mut Tracer::new()).unwrap();
+ let doc = typst::compile(&world).output.unwrap();
let pos = jump_from_cursor(&doc, &world.main, cursor);
assert_eq!(pos.is_some(), expected.is_some());
if let (Some(pos), Some(expected)) = (pos, expected) {
diff --git a/crates/typst-ide/src/tooltip.rs b/crates/typst-ide/src/tooltip.rs
index 4864a266..3bf8bb14 100644
--- a/crates/typst-ide/src/tooltip.rs
+++ b/crates/typst-ide/src/tooltip.rs
@@ -2,7 +2,8 @@ use std::fmt::Write;
use ecow::{eco_format, EcoString};
use if_chain::if_chain;
-use typst::eval::{CapturesVisitor, Tracer};
+use typst::engine::Sink;
+use typst::eval::CapturesVisitor;
use typst::foundations::{repr, Capturer, CastInfo, Repr, Value};
use typst::layout::Length;
use typst::model::Document;
@@ -79,7 +80,7 @@ fn expr_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<Tooltip> {
let mut last = None;
let mut pieces: Vec<EcoString> = vec![];
let mut iter = values.iter();
- for (value, _) in (&mut iter).take(Tracer::MAX_VALUES - 1) {
+ for (value, _) in (&mut iter).take(Sink::MAX_VALUES - 1) {
if let Some((prev, count)) = &mut last {
if *prev == value {
*count += 1;
@@ -253,7 +254,6 @@ fn font_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<Tooltip> {
#[cfg(test)]
mod tests {
- use typst::eval::Tracer;
use typst::syntax::Side;
use super::{tooltip, Tooltip};
@@ -270,7 +270,7 @@ mod tests {
#[track_caller]
fn test(text: &str, cursor: usize, side: Side, expected: Option<Tooltip>) {
let world = TestWorld::new(text);
- let doc = typst::compile(&world, &mut Tracer::new()).ok();
+ let doc = typst::compile(&world).output.ok();
assert_eq!(tooltip(&world, doc.as_ref(), &world.main, cursor, side), expected);
}
diff --git a/crates/typst/src/diag.rs b/crates/typst/src/diag.rs
index db8a93fd..6dd88556 100644
--- a/crates/typst/src/diag.rs
+++ b/crates/typst/src/diag.rs
@@ -138,6 +138,15 @@ pub use {
/// A result that can carry multiple source errors.
pub type SourceResult<T> = Result<T, EcoVec<SourceDiagnostic>>;
+/// An output alongside warnings generated while producing it.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct Warned<T> {
+ /// The produced output.
+ pub output: T,
+ /// Warnings generated while producing the output.
+ pub warnings: EcoVec<SourceDiagnostic>,
+}
+
/// An error or warning in a source file.
///
/// The contained spans will only be detached if any of the input source files
diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs
index a57a8f1c..ac61cc33 100644
--- a/crates/typst/src/engine.rs
+++ b/crates/typst/src/engine.rs
@@ -1,13 +1,15 @@
//! Definition of the central compilation context.
+use std::collections::HashSet;
use std::sync::atomic::{AtomicUsize, Ordering};
use comemo::{Track, Tracked, TrackedMut, Validate};
+use ecow::EcoVec;
-use crate::diag::SourceResult;
-use crate::eval::Tracer;
+use crate::diag::{SourceDiagnostic, SourceResult};
+use crate::foundations::{Styles, Value};
use crate::introspection::Introspector;
-use crate::syntax::FileId;
+use crate::syntax::{FileId, Span};
use crate::World;
/// Holds all data needed during compilation.
@@ -16,18 +18,20 @@ pub struct Engine<'a> {
pub world: Tracked<'a, dyn World + 'a>,
/// Provides access to information about the document.
pub introspector: Tracked<'a, Introspector>,
+ /// May hold a span that is currently under inspection.
+ pub traced: Tracked<'a, Traced>,
+ /// A pure sink for warnings, delayed errors, and spans under inspection.
+ pub sink: TrackedMut<'a, Sink>,
/// The route the engine took during compilation. This is used to detect
/// cyclic imports and excessive nesting.
pub route: Route<'a>,
- /// The tracer for inspection of the values an expression produces.
- pub tracer: TrackedMut<'a, Tracer>,
}
impl Engine<'_> {
/// Performs a fallible operation that does not immediately terminate further
/// execution. Instead it produces a delayed error that is only promoted to
/// a fatal one if it remains at the end of the introspection loop.
- pub fn delayed<F, T>(&mut self, f: F) -> T
+ pub fn delay<F, T>(&mut self, f: F) -> T
where
F: FnOnce(&mut Self) -> SourceResult<T>,
T: Default,
@@ -35,13 +39,112 @@ impl Engine<'_> {
match f(self) {
Ok(value) => value,
Err(errors) => {
- self.tracer.delay(errors);
+ self.sink.delay(errors);
T::default()
}
}
}
}
+/// May hold a span that is currently under inspection.
+#[derive(Default)]
+pub struct Traced(Option<Span>);
+
+impl Traced {
+ /// Wraps a to-be-traced `Span`.
+ ///
+ /// Call `Traced::default()` to trace nothing.
+ pub fn new(traced: Span) -> Self {
+ Self(Some(traced))
+ }
+}
+
+#[comemo::track]
+impl Traced {
+ /// Returns the traced span _if_ it is part of the given source file or
+ /// `None` otherwise.
+ ///
+ /// We hide the span if it isn't in the given file so that only results for
+ /// the file with the traced span are invalidated.
+ pub fn get(&self, id: FileId) -> Option<Span> {
+ if self.0.and_then(Span::id) == Some(id) {
+ self.0
+ } else {
+ None
+ }
+ }
+}
+
+/// A push-only sink for delayed errors, warnings, and traced values.
+///
+/// All tracked methods of this type are of the form `(&mut self, ..) -> ()`, so
+/// in principle they do not need validation (though that optimization is not
+/// yet implemented in comemo).
+#[derive(Default, Clone)]
+pub struct Sink {
+ /// Delayed errors: Those are errors that we can ignore until the last
+ /// iteration. For instance, show rules may throw during earlier iterations
+ /// because the introspector is not yet ready. We first ignore that and
+ /// proceed with empty content and only if the error remains by the end
+ /// of the last iteration, we promote it.
+ delayed: EcoVec<SourceDiagnostic>,
+ /// Warnings emitted during iteration.
+ warnings: EcoVec<SourceDiagnostic>,
+ /// Hashes of all warning's spans and messages for warning deduplication.
+ warnings_set: HashSet<u128>,
+ /// A sequence of traced values for a span.
+ values: EcoVec<(Value, Option<Styles>)>,
+}
+
+impl Sink {
+ /// The maximum number of traced values.
+ pub const MAX_VALUES: usize = 10;
+
+ /// Create a new empty sink.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Get the stored delayed errors.
+ pub fn delayed(&mut self) -> EcoVec<SourceDiagnostic> {
+ std::mem::take(&mut self.delayed)
+ }
+
+ /// Get the stored warnings.
+ pub fn warnings(self) -> EcoVec<SourceDiagnostic> {
+ self.warnings
+ }
+
+ /// Get the values for the traced span.
+ pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
+ self.values
+ }
+}
+
+#[comemo::track]
+impl Sink {
+ /// Push delayed errors.
+ pub fn delay(&mut self, errors: EcoVec<SourceDiagnostic>) {
+ self.delayed.extend(errors);
+ }
+
+ /// Add a warning.
+ pub fn warn(&mut self, warning: SourceDiagnostic) {
+ // Check if warning is a duplicate.
+ let hash = crate::utils::hash128(&(&warning.span, &warning.message));
+ if self.warnings_set.insert(hash) {
+ self.warnings.push(warning);
+ }
+ }
+
+ /// Trace a value and optionally styles for the traced span.
+ pub fn value(&mut self, value: Value, styles: Option<Styles>) {
+ if self.values.len() < Self::MAX_VALUES {
+ self.values.push((value, styles));
+ }
+ }
+}
+
/// The route the engine took during compilation. This is used to detect
/// cyclic imports and excessive nesting.
pub struct Route<'a> {
diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs
index d4b81f02..278c3afb 100644
--- a/crates/typst/src/eval/call.rs
+++ b/crates/typst/src/eval/call.rs
@@ -2,8 +2,8 @@ use comemo::{Tracked, TrackedMut};
use ecow::{eco_format, EcoVec};
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
-use crate::engine::Engine;
-use crate::eval::{Access, Eval, FlowEvent, Route, Tracer, Vm};
+use crate::engine::{Engine, Sink, Traced};
+use crate::eval::{Access, Eval, FlowEvent, Route, Vm};
use crate::foundations::{
call_method_mut, is_mutating_method, Arg, Args, Bytes, Capturer, Closure, Content,
Context, Func, IntoValue, NativeElement, Scope, Scopes, Value,
@@ -275,8 +275,9 @@ pub(crate) fn call_closure(
closure: &LazyHash<Closure>,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
context: Tracked<Context>,
mut args: Args,
) -> SourceResult<Value> {
@@ -294,8 +295,9 @@ pub(crate) fn call_closure(
let engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route),
- tracer,
};
// Prepare VM.
diff --git a/crates/typst/src/eval/import.rs b/crates/typst/src/eval/import.rs
index fbd55b7c..da07e666 100644
--- a/crates/typst/src/eval/import.rs
+++ b/crates/typst/src/eval/import.rs
@@ -35,7 +35,7 @@ impl Eval for ast::ModuleImport<'_> {
if let ast::Expr::Ident(ident) = self.source() {
if ident.as_str() == new_name.as_str() {
// Warn on `import x as x`
- vm.engine.tracer.warn(warning!(
+ vm.engine.sink.warn(warning!(
new_name.span(),
"unnecessary import rename to same name",
));
@@ -110,7 +110,7 @@ impl Eval for ast::ModuleImport<'_> {
if renamed_item.original_name().as_str()
== renamed_item.new_name().as_str()
{
- vm.engine.tracer.warn(warning!(
+ vm.engine.sink.warn(warning!(
renamed_item.new_name().span(),
"unnecessary import rename to same name",
));
@@ -185,8 +185,9 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Mo
let point = || Tracepoint::Import;
Ok(eval(
vm.world(),
+ vm.engine.traced,
+ TrackedMut::reborrow_mut(&mut vm.engine.sink),
vm.engine.route.track(),
- TrackedMut::reborrow_mut(&mut vm.engine.tracer),
&source,
)
.trace(vm.world(), point, span)?
@@ -209,8 +210,9 @@ fn import_file(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> {
let point = || Tracepoint::Import;
eval(
world,
+ vm.engine.traced,
+ TrackedMut::reborrow_mut(&mut vm.engine.sink),
vm.engine.route.track(),
- TrackedMut::reborrow_mut(&mut vm.engine.tracer),
&source,
)
.trace(world, point, span)
diff --git a/crates/typst/src/eval/markup.rs b/crates/typst/src/eval/markup.rs
index d43e4495..e38f137d 100644
--- a/crates/typst/src/eval/markup.rs
+++ b/crates/typst/src/eval/markup.rs
@@ -134,7 +134,7 @@ impl Eval for ast::Strong<'_> {
let body = self.body();
if body.exprs().next().is_none() {
vm.engine
- .tracer
+ .sink
.warn(warning!(
self.span(), "no text within stars";
hint: "using multiple consecutive stars (e.g. **) has no additional effect",
@@ -152,7 +152,7 @@ impl Eval for ast::Emph<'_> {
let body = self.body();
if body.exprs().next().is_none() {
vm.engine
- .tracer
+ .sink
.warn(warning!(
self.span(), "no text within underscores";
hint: "using multiple consecutive underscores (e.g. __) has no additional effect"
diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs
index 2e5eeafd..e4221df7 100644
--- a/crates/typst/src/eval/mod.rs
+++ b/crates/typst/src/eval/mod.rs
@@ -11,12 +11,10 @@ mod import;
mod markup;
mod math;
mod rules;
-mod tracer;
mod vm;
pub use self::call::*;
pub use self::import::*;
-pub use self::tracer::*;
pub use self::vm::*;
pub(crate) use self::access::*;
@@ -26,7 +24,7 @@ pub(crate) use self::flow::*;
use comemo::{Track, Tracked, TrackedMut};
use crate::diag::{bail, SourceResult};
-use crate::engine::{Engine, Route};
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{Cast, Context, Module, NativeElement, Scope, Scopes, Value};
use crate::introspection::Introspector;
use crate::math::EquationElem;
@@ -38,8 +36,9 @@ use crate::World;
#[typst_macros::time(name = "eval", span = source.root().span())]
pub fn eval(
world: Tracked<dyn World + '_>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
source: &Source,
) -> SourceResult<Module> {
// Prevent cyclic evaluation.
@@ -52,9 +51,10 @@ pub fn eval(
let introspector = Introspector::default();
let engine = Engine {
world,
- route: Route::extend(route).with_id(id),
introspector: introspector.track(),
- tracer,
+ traced,
+ sink,
+ route: Route::extend(route).with_id(id),
};
// Prepare VM.
@@ -115,13 +115,15 @@ pub fn eval_string(
}
// Prepare the engine.
- let mut tracer = Tracer::new();
+ let mut sink = Sink::new();
let introspector = Introspector::default();
+ let traced = Traced::default();
let engine = Engine {
world,
introspector: introspector.track(),
+ traced: traced.track(),
+ sink: sink.track_mut(),
route: Route::default(),
- tracer: tracer.track_mut(),
};
// Prepare VM.
diff --git a/crates/typst/src/eval/tracer.rs b/crates/typst/src/eval/tracer.rs
deleted file mode 100644
index 30c640f3..00000000
--- a/crates/typst/src/eval/tracer.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::collections::HashSet;
-
-use ecow::EcoVec;
-
-use crate::diag::SourceDiagnostic;
-use crate::foundations::{Styles, Value};
-use crate::syntax::{FileId, Span};
-use crate::utils::hash128;
-
-/// Traces warnings and which values existed for an expression at a span.
-#[derive(Default, Clone)]
-pub struct Tracer {
- inspected: Option<Span>,
- warnings: EcoVec<SourceDiagnostic>,
- warnings_set: HashSet<u128>,
- delayed: EcoVec<SourceDiagnostic>,
- values: EcoVec<(Value, Option<Styles>)>,
-}
-
-impl Tracer {
- /// The maximum number of inspected values.
- pub const MAX_VALUES: usize = 10;
-
- /// Create a new tracer.
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Get the stored delayed errors.
- pub fn delayed(&mut self) -> EcoVec<SourceDiagnostic> {
- std::mem::take(&mut self.delayed)
- }
-
- /// Get the stored warnings.
- pub fn warnings(self) -> EcoVec<SourceDiagnostic> {
- self.warnings
- }
-
- /// Mark a span as inspected. All values observed for this span can be
- /// retrieved via `values` later.
- pub fn inspect(&mut self, span: Span) {
- self.inspected = Some(span);
- }
-
- /// Get the values for the inspected span.
- pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
- self.values
- }
-}
-
-#[comemo::track]
-impl Tracer {
- /// Push delayed errors.
- pub fn delay(&mut self, errors: EcoVec<SourceDiagnostic>) {
- self.delayed.extend(errors);
- }
-
- /// Add a warning.
- pub fn warn(&mut self, warning: SourceDiagnostic) {
- // Check if warning is a duplicate.
- let hash = hash128(&(&warning.span, &warning.message));
- if self.warnings_set.insert(hash) {
- self.warnings.push(warning);
- }
- }
-
- /// The inspected span if it is part of the given source file.
- pub fn inspected(&self, id: FileId) -> Option<Span> {
- if self.inspected.and_then(Span::id) == Some(id) {
- self.inspected
- } else {
- None
- }
- }
-
- /// Trace a value for the span.
- pub fn value(&mut self, value: Value, styles: Option<Styles>) {
- if self.values.len() < Self::MAX_VALUES {
- self.values.push((value, styles));
- }
- }
-}
diff --git a/crates/typst/src/eval/vm.rs b/crates/typst/src/eval/vm.rs
index be43b5ba..27960eb6 100644
--- a/crates/typst/src/eval/vm.rs
+++ b/crates/typst/src/eval/vm.rs
@@ -32,7 +32,7 @@ impl<'a> Vm<'a> {
scopes: Scopes<'a>,
target: Span,
) -> Self {
- let inspected = target.id().and_then(|id| engine.tracer.inspected(id));
+ let inspected = target.id().and_then(|id| engine.traced.get(id));
Self { engine, context, flow: None, scopes, inspected }
}
@@ -54,7 +54,7 @@ impl<'a> Vm<'a> {
#[cold]
pub fn trace(&mut self, value: Value) {
self.engine
- .tracer
+ .sink
.value(value.clone(), self.context.styles().ok().map(|s| s.to_map()));
}
}
diff --git a/crates/typst/src/foundations/func.rs b/crates/typst/src/foundations/func.rs
index f5b4b3ca..dc5ea8df 100644
--- a/crates/typst/src/foundations/func.rs
+++ b/crates/typst/src/foundations/func.rs
@@ -297,8 +297,9 @@ impl Func {
closure,
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
context,
args,
),
diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs
index df16026f..13ea4d14 100644
--- a/crates/typst/src/introspection/counter.rs
+++ b/crates/typst/src/introspection/counter.rs
@@ -6,8 +6,7 @@ use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use smallvec::{smallvec, SmallVec};
use crate::diag::{bail, At, HintedStrResult, SourceResult};
-use crate::engine::{Engine, Route};
-use crate::eval::Tracer;
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{
cast, elem, func, scope, select_where, ty, Args, Array, Construct, Content, Context,
Element, Func, IntoValue, Label, LocatableSelector, NativeElement, Packed, Repr,
@@ -281,8 +280,9 @@ impl Counter {
self.sequence_impl(
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
)
}
@@ -292,14 +292,16 @@ impl Counter {
&self,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
let mut engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route).unnested(),
- tracer,
};
let mut state = CounterState::init(&self.0);
diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs
index bf97c874..be114c86 100644
--- a/crates/typst/src/introspection/state.rs
+++ b/crates/typst/src/introspection/state.rs
@@ -2,8 +2,7 @@ use comemo::{Track, Tracked, TrackedMut};
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use crate::diag::{bail, At, SourceResult};
-use crate::engine::{Engine, Route};
-use crate::eval::Tracer;
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{
cast, elem, func, scope, select_where, ty, Args, Construct, Content, Context, Func,
LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str, StyleChain,
@@ -214,8 +213,9 @@ impl State {
self.sequence_impl(
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
)
}
@@ -225,14 +225,16 @@ impl State {
&self,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
) -> SourceResult<EcoVec<Value>> {
let mut engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route).unnested(),
- tracer,
};
let mut state = self.init.clone();
let mut stops = eco_vec![state.clone()];
diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs
index e6e3d88c..49bad3f7 100644
--- a/crates/typst/src/layout/inline/mod.rs
+++ b/crates/typst/src/layout/inline/mod.rs
@@ -11,8 +11,7 @@ use self::shaping::{
END_PUNCT_PAT,
};
use crate::diag::{bail, SourceResult};
-use crate::engine::{Engine, Route};
-use crate::eval::Tracer;
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{Packed, Resolve, Smart, StyleChain};
use crate::introspection::{Introspector, Locator, LocatorLink, Tag, TagElem};
use crate::layout::{
@@ -45,8 +44,9 @@ pub(crate) fn layout_inline(
children: &StyleVec,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
locator: Tracked<Locator>,
styles: StyleChain,
consecutive: bool,
@@ -58,8 +58,9 @@ pub(crate) fn layout_inline(
let mut engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route),
- tracer,
};
// Collect all text into one string for BiDi analysis.
@@ -83,8 +84,9 @@ pub(crate) fn layout_inline(
children,
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
locator.track(),
styles,
consecutive,
diff --git a/crates/typst/src/layout/mod.rs b/crates/typst/src/layout/mod.rs
index 843b43f5..85cdbae7 100644
--- a/crates/typst/src/layout/mod.rs
+++ b/crates/typst/src/layout/mod.rs
@@ -72,8 +72,7 @@ pub(crate) use self::inline::*;
use comemo::{Track, Tracked, TrackedMut};
use crate::diag::{bail, SourceResult};
-use crate::engine::{Engine, Route};
-use crate::eval::Tracer;
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{category, Category, Content, Scope, StyleChain};
use crate::introspection::{Introspector, Locator, LocatorLink};
use crate::model::Document;
@@ -137,16 +136,18 @@ impl Content {
content: &Content,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
styles: StyleChain,
) -> SourceResult<Document> {
let mut locator = Locator::root().split();
let mut engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route).unnested(),
- tracer,
};
let arenas = Arenas::default();
let (document, styles) =
@@ -158,8 +159,9 @@ impl Content {
self,
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
styles,
)
}
@@ -178,8 +180,9 @@ impl Content {
content: &Content,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
+ traced: Tracked<Traced>,
+ sink: TrackedMut<Sink>,
route: Tracked<Route>,
- tracer: TrackedMut<Tracer>,
locator: Tracked<Locator>,
styles: StyleChain,
regions: Regions,
@@ -189,8 +192,9 @@ impl Content {
let mut engine = Engine {
world,
introspector,
+ traced,
+ sink,
route: Route::extend(route),
- tracer,
};
if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
@@ -218,8 +222,9 @@ impl Content {
self,
engine.world,
engine.introspector,
+ engine.traced,
+ TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
- TrackedMut::reborrow_mut(&mut engine.tracer),
locator.track(),
styles,
regions,
diff --git a/crates/typst/src/lib.rs b/crates/typst/src/lib.rs
index 6d445edd..50575d12 100644
--- a/crates/typst/src/lib.rs
+++ b/crates/typst/src/lib.rs
@@ -63,11 +63,10 @@ use comemo::{Track, Tracked, Validate};
use ecow::{EcoString, EcoVec};
use typst_timing::{timed, TimingScope};
-use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult};
-use crate::engine::{Engine, Route};
-use crate::eval::Tracer;
+use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult, Warned};
+use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{
- Array, Bytes, Content, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
+ Array, Bytes, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
};
use crate::introspection::Introspector;
use crate::layout::{Alignment, Dir};
@@ -78,62 +77,68 @@ use crate::text::{Font, FontBook};
use crate::utils::LazyHash;
use crate::visualize::Color;
-/// Compile a source file into a fully layouted document.
+/// Compile sources into a fully layouted document.
///
/// - Returns `Ok(document)` if there were no fatal errors.
/// - Returns `Err(errors)` if there were fatal errors.
-///
-/// Requires a mutable reference to a tracer. Such a tracer can be created with
-/// `Tracer::new()`. Independently of whether compilation succeeded, calling
-/// `tracer.warnings()` after compilation will return all compiler warnings.
-#[typst_macros::time(name = "compile")]
-pub fn compile(world: &dyn World, tracer: &mut Tracer) -> SourceResult<Document> {
- // Call `track` on the world just once to keep comemo's ID stable.
- let world = world.track();
-
- // Try to evaluate the source file into a module.
- let module = crate::eval::eval(
- world,
- Route::default().track(),
- tracer.track_mut(),
- &world.main(),
- )
- .map_err(deduplicate)?;
+#[typst_macros::time]
+pub fn compile(world: &dyn World) -> Warned<SourceResult<Document>> {
+ let mut sink = Sink::new();
+ let output = compile_inner(world.track(), Traced::default().track(), &mut sink)
+ .map_err(deduplicate);
+ Warned { output, warnings: sink.warnings() }
+}
- // Typeset the module's content, relayouting until convergence.
- typeset(world, tracer, &module.content()).map_err(deduplicate)
+/// Compiles sources and returns all values and styles observed at the given
+/// `span` during compilation.
+#[typst_macros::time]
+pub fn trace(world: &dyn World, span: Span) -> EcoVec<(Value, Option<Styles>)> {
+ let mut sink = Sink::new();
+ let traced = Traced::new(span);
+ compile_inner(world.track(), traced.track(), &mut sink).ok();
+ sink.values()
}
/// Relayout until introspection converges.
-fn typeset(
+fn compile_inner(
world: Tracked<dyn World + '_>,
- tracer: &mut Tracer,
- content: &Content,
+ traced: Tracked<Traced>,
+ sink: &mut Sink,
) -> SourceResult<Document> {
- // The name of the iterations for timing scopes.
- const ITER_NAMES: &[&str] =
- &["typeset (1)", "typeset (2)", "typeset (3)", "typeset (4)", "typeset (5)"];
-
let library = world.library();
let styles = StyleChain::new(&library.styles);
+ // First evaluate the main source file into a module.
+ let content = crate::eval::eval(
+ world,
+ traced,
+ sink.track_mut(),
+ Route::default().track(),
+ &world.main(),
+ )?
+ .content();
+
let mut iter = 0;
let mut document = Document::default();
// Relayout until all introspections stabilize.
// If that doesn't happen within five attempts, we give up.
loop {
+ // The name of the iterations for timing scopes.
+ const ITER_NAMES: &[&str] =
+ &["layout (1)", "layout (2)", "layout (3)", "layout (4)", "layout (5)"];
let _scope = TimingScope::new(ITER_NAMES[iter], None);
// Clear delayed errors.
- tracer.delayed();
+ sink.delayed();
let constraint = <Introspector as Validate>::Constraint::new();
let mut engine = Engine {
world,
- route: Route::default(),
- tracer: tracer.track_mut(),
introspector: document.introspector.track_with(&constraint),
+ traced,
+ sink: sink.track_mut(),
+ route: Route::default(),
};
// Layout!
@@ -146,7 +151,7 @@ fn typeset(
}
if iter >= 5 {
- tracer.warn(warning!(
+ sink.warn(warning!(
Span::detached(), "layout did not converge within 5 attempts";
hint: "check if any states or queries are updating themselves"
));
@@ -155,7 +160,7 @@ fn typeset(
}
// Promote delayed errors.
- let delayed = tracer.delayed();
+ let delayed = sink.delayed();
if !delayed.is_empty() {
return Err(delayed);
}
diff --git a/crates/typst/src/realize/process.rs b/crates/typst/src/realize/process.rs
index a0ba8fdb..150f07ab 100644
--- a/crates/typst/src/realize/process.rs
+++ b/crates/typst/src/realize/process.rs
@@ -62,7 +62,7 @@ pub fn process(
//
// This way, we can ignore errors that only occur in earlier
// iterations and also show more useful errors at once.
- engine.delayed(|engine| show(engine, target, step, styles.chain(&map)))
+ engine.delay(|engine| show(engine, target, step, styles.chain(&map)))
}
None => target,
};
diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs
index 36b3de26..7648f08f 100644
--- a/crates/typst/src/text/mod.rs
+++ b/crates/typst/src/text/mod.rs
@@ -132,7 +132,7 @@ pub struct TextElem {
let book = engine.world.book();
for family in &font_list.v {
if !book.contains_family(family.as_str()) {
- engine.tracer.warn(warning!(
+ engine.sink.warn(warning!(
font_list.span,
"unknown font family: {}",
family.as_str(),