diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs index 0608485ad..68e4f323d 100644 --- a/crates/typst/src/engine.rs +++ b/crates/typst/src/engine.rs @@ -85,6 +85,47 @@ impl Engine<'_> { pairs.into_iter().map(|(output, _)| output) } + + /// Executes some code with a tracepoint for diagnostics. + /// The tracepoint is added to any diagnostics returned by the function, + /// as well as any warnings emitted by it. + pub fn tracepoint( + &mut self, + make_point: M, + span: Span, + f: F, + ) -> SourceResult + where + F: FnOnce(&mut Engine) -> SourceResult, + M: Copy + Fn() -> Tracepoint, + { + let Engine { world, introspector, traced, ref route, .. } = *self; + + // Create a temporary sink to accumulate all warnings produced by + // this call (either directly or due to a nested call). Later, we + // add a tracepoint to those warnings, indicating this call was + // part of the call stack that led to the warning being raised, + // thus allowing suppression of the warning through this call. + let mut sink = Sink::new(); + let mut engine = Engine { + world, + introspector, + traced, + sink: sink.track_mut(), + route: route.clone(), + }; + + // Trace errors immediately, followed by warnings on the sink. + let call_result = f(&mut engine).trace(world, make_point, span); + sink.trace_warnings(world, make_point, span); + + // Push the accumulated warnings and other fields back to the + // original sink after we have modified them. This is needed so the + // warnings are properly returned by compilation later. + self.sink.extend(sink.delayed, sink.warnings, sink.values); + + call_result + } } /// May hold a span that is currently under inspection. diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs index d00f4225b..f19e881bd 100644 --- a/crates/typst/src/eval/call.rs +++ b/crates/typst/src/eval/call.rs @@ -1,4 +1,4 @@ -use comemo::{Track, Tracked, TrackedMut}; +use comemo::{Tracked, TrackedMut}; use ecow::{eco_format, EcoVec}; use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint}; @@ -165,31 +165,12 @@ impl Eval for ast::FuncCall<'_> { let point = || Tracepoint::Call(func.name().map(Into::into)); let f = || { - // Create a temporary sink to accumulate all warnings produced by - // this call (either directly or due to a nested call). Later, we - // add a tracepoint to those warnings, indicating this call was - // part of the call stack that led to the warning being raised, - // thus allowing suppression of the warning through this call. - let mut local_sink = Sink::new(); - let mut engine = Engine { - sink: local_sink.track_mut(), - route: vm.engine.route.clone(), - ..vm.engine - }; - - let call_result = + // Add this function call as a tracepoint to the returned + // diagnostics. This allows visualizing which calls led to them, + // but also allows suppressing warnings at each tracepoint. + vm.engine.tracepoint(point, span, |mut engine| { func.call(&mut engine, vm.context, args) - .trace(vm.world(), point, span); - - local_sink.trace_warnings(vm.world(), point, span); - - // Push the accumulated warnings and other fields back to the - // original sink after we have modified them. This is needed so the - // warnings are properly returned by compilation later. - let (delayed, warnings, values) = local_sink.take(); - vm.engine.sink.extend(delayed, warnings, values); - - call_result + }) }; // Stacker is broken on WASM.