diff options
Diffstat (limited to 'crates')
89 files changed, 1204 insertions, 983 deletions
diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs index f3e417d5..8c5117f7 100644 --- a/crates/typst-ide/src/analyze.rs +++ b/crates/typst-ide/src/analyze.rs @@ -1,9 +1,10 @@ use comemo::Track; use ecow::{eco_vec, EcoString, EcoVec}; -use typst::eval::{Route, Tracer, Vm}; +use typst::engine::{Engine, Route}; +use typst::eval::{Tracer, Vm}; use typst::foundations::{Label, Scopes, Value}; use typst::introspection::{Introspector, Locator}; -use typst::layout::{Frame, Vt}; +use typst::layout::Frame; use typst::model::BibliographyElem; use typst::syntax::{ast, LinkedNode, Span, SyntaxKind}; use typst::World; @@ -46,7 +47,6 @@ pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec<Value> { /// Try to load a module from the current source file. pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> { - let id = source.span().id()?; let source = analyze_expr(world, source).into_iter().next()?; if source.scope().is_some() { return Some(source); @@ -55,15 +55,15 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> { let mut locator = Locator::default(); let introspector = Introspector::default(); let mut tracer = Tracer::new(); - let vt = Vt { + let engine = Engine { world: world.track(), + route: Route::default(), introspector: introspector.track(), locator: &mut locator, tracer: tracer.track_mut(), }; - let route = Route::default(); - let mut vm = Vm::new(vt, route.track(), Some(id), Scopes::new(Some(world.library()))); + let mut vm = Vm::new(engine, Scopes::new(Some(world.library())), Span::detached()); typst::eval::import(&mut vm, source, Span::detached(), true) .ok() .map(Value::Module) diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs index 9791427b..ce80cc66 100644 --- a/crates/typst-macros/src/elem.rs +++ b/crates/typst-macros/src/elem.rs @@ -1083,7 +1083,7 @@ fn create_construct_impl(element: &Elem) -> TokenStream { quote! { impl #foundations::Construct for #ident { fn construct( - vm: &mut ::typst::eval::Vm, + engine: &mut ::typst::engine::Engine, args: &mut #foundations::Args, ) -> ::typst::diag::SourceResult<#foundations::Content> { #(#pre)* @@ -1115,7 +1115,7 @@ fn create_set_impl(element: &Elem) -> TokenStream { quote! { impl #foundations::Set for #ident { fn set( - vm: &mut ::typst::eval::Vm, + engine: &mut ::typst::engine::Engine, args: &mut #foundations::Args, ) -> ::typst::diag::SourceResult<#foundations::Styles> { let mut styles = #foundations::Styles::new(); diff --git a/crates/typst-macros/src/func.rs b/crates/typst-macros/src/func.rs index 8537ac4f..953df428 100644 --- a/crates/typst-macros/src/func.rs +++ b/crates/typst-macros/src/func.rs @@ -36,8 +36,7 @@ struct Func { #[derive(Default)] struct SpecialParams { self_: Option<Param>, - vm: bool, - vt: bool, + engine: bool, args: bool, span: bool, } @@ -171,8 +170,7 @@ fn parse_param( }; match ident.to_string().as_str() { - "vm" => special.vm = true, - "vt" => special.vt = true, + "engine" => special.engine = true, "args" => special.args = true, "span" => special.span = true, _ => { @@ -322,13 +320,12 @@ fn create_wrapper_closure(func: &Func) -> TokenStream { .as_ref() .map(bind) .map(|tokens| quote! { #tokens, }); - let vm_ = func.special.vm.then(|| quote! { vm, }); - let vt_ = func.special.vt.then(|| quote! { &mut vm.vt, }); + let vt_ = func.special.engine.then(|| quote! { engine, }); let args_ = func.special.args.then(|| quote! { args, }); let span_ = func.special.span.then(|| quote! { args.span, }); let forwarded = func.params.iter().filter(|param| !param.external).map(bind); quote! { - __typst_func(#self_ #vm_ #vt_ #args_ #span_ #(#forwarded,)*) + __typst_func(#self_ #vt_ #args_ #span_ #(#forwarded,)*) } }; @@ -336,7 +333,7 @@ fn create_wrapper_closure(func: &Func) -> TokenStream { let ident = &func.ident; let parent = func.parent.as_ref().map(|ty| quote! { #ty:: }); quote! { - |vm, args| { + |engine, args| { let __typst_func = #parent #ident; #handlers #finish diff --git a/crates/typst-syntax/src/span.rs b/crates/typst-syntax/src/span.rs index 14e5e216..8138a316 100644 --- a/crates/typst-syntax/src/span.rs +++ b/crates/typst-syntax/src/span.rs @@ -2,6 +2,8 @@ use std::fmt::{self, Debug, Formatter}; use std::num::NonZeroU64; use std::ops::Range; +use ecow::EcoString; + use crate::FileId; /// A unique identifier for a syntax node. @@ -80,6 +82,14 @@ impl Span { pub const fn number(self) -> u64 { self.0.get() & ((1 << Self::BITS) - 1) } + + /// Resolve a file location relative to this span's source. + pub fn resolve_path(self, path: &str) -> Result<FileId, EcoString> { + let Some(file) = self.id() else { + return Err("cannot access file system from here".into()); + }; + Ok(file.join(path)) + } } /// A value with a span locating it in the source code. diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs new file mode 100644 index 00000000..189034cf --- /dev/null +++ b/crates/typst/src/engine.rs @@ -0,0 +1,159 @@ +use std::cell::Cell; + +use comemo::{Track, Tracked, TrackedMut, Validate}; + +use crate::diag::SourceResult; +use crate::eval::Tracer; +use crate::introspection::{Introspector, Locator}; +use crate::syntax::FileId; +use crate::World; + +/// The maxmium stack nesting depth. +const MAX_DEPTH: usize = 64; + +/// Holds all data needed during compilation. +pub struct Engine<'a> { + /// The compilation environment. + pub world: Tracked<'a, dyn World + 'a>, + /// Provides access to information about the document. + pub introspector: Tracked<'a, Introspector>, + /// The route the engine took during compilation. This is used to detect + /// cyclic imports and too much nesting. + pub route: Route<'a>, + /// Provides stable identities to elements. + pub locator: &'a mut Locator<'a>, + /// The tracer for inspection of the values an expression produces. + pub tracer: TrackedMut<'a, Tracer>, +} + +impl Engine<'_> { + /// Perform 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 + where + F: FnOnce(&mut Self) -> SourceResult<T>, + T: Default, + { + match f(self) { + Ok(value) => value, + Err(errors) => { + self.tracer.delay(errors); + T::default() + } + } + } +} + +/// The route the engine took during compilation. This is used to detect +/// cyclic imports and too much nesting. +#[derive(Clone)] +pub struct Route<'a> { + // We need to override the constraint's lifetime here so that `Tracked` is + // covariant over the constraint. If it becomes invariant, we're in for a + // world of lifetime pain. + outer: Option<Tracked<'a, Self, <Route<'static> as Validate>::Constraint>>, + /// This is set if this route segment was inserted through the start of a + /// module evaluation. + id: Option<FileId>, + /// This is set whenever we enter a function, nested layout, or are applying + /// a show rule. The length of this segment plus the lengths of all `outer` + /// route segments make up the length of the route. If the length of the + /// route exceeds `MAX_DEPTH`, then we throw a "maximum ... depth exceeded" + /// error. + len: usize, + /// The upper bound we've established for the parent chain length. We don't + /// know the exact length (that would defeat the whole purpose because it + /// would prevent cache reuse of some computation at different, + /// non-exceeding depths). + upper: Cell<usize>, +} + +impl<'a> Route<'a> { + /// Create a new, empty route. + pub fn root() -> Self { + Self { id: None, outer: None, len: 0, upper: Cell::new(0) } + } + + /// Insert a new id into the route. + /// + /// You must guarantee that `outer` lives longer than the resulting + /// route is ever used. + pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self { + Route { + outer: Some(outer), + id: Some(id), + len: 0, + upper: Cell::new(usize::MAX), + } + } + + /// Extend the route without another id. + pub fn extend(outer: Tracked<'a, Self>) -> Self { + Route { + outer: Some(outer), + id: None, + len: 1, + upper: Cell::new(usize::MAX), + } + } + + /// Start tracking this route. + /// + /// In comparison to [`Track::track`], this method skips this chain link + /// if it does not contribute anything. + pub fn track(&self) -> Tracked<'_, Self> { + match self.outer { + Some(outer) if self.id.is_none() && self.len == 0 => outer, + _ => Track::track(self), + } + } + + /// Increase the nesting depth for this route segment. + pub fn increase(&mut self) { + self.len += 1; + } + + /// Decrease the nesting depth for this route segment. + pub fn decrease(&mut self) { + self.len -= 1; + } + + /// Check whether the nesting depth exceeds the limit. + pub fn exceeding(&self) -> bool { + !self.within(MAX_DEPTH) + } +} + +#[comemo::track] +impl<'a> Route<'a> { + /// Whether the given id is part of the route. + pub fn contains(&self, id: FileId) -> bool { + self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id)) + } + + /// Whether the route's depth is less than or equal to the given depth. + pub fn within(&self, depth: usize) -> bool { + if self.upper.get().saturating_add(self.len) <= depth { + return true; + } + + match self.outer { + Some(_) if depth < self.len => false, + Some(outer) => { + let within = outer.within(depth - self.len); + if within && depth < self.upper.get() { + self.upper.set(depth); + } + within + } + None => true, + } + } +} + +impl Default for Route<'_> { + fn default() -> Self { + Self::root() + } +} diff --git a/crates/typst/src/eval/access.rs b/crates/typst/src/eval/access.rs index ff0b7512..99b2f72e 100644 --- a/crates/typst/src/eval/access.rs +++ b/crates/typst/src/eval/access.rs @@ -31,7 +31,7 @@ impl Access for ast::Ident<'_> { let span = self.span(); let value = vm.scopes.get_mut(&self).at(span)?; if vm.inspected == Some(span) { - vm.vt.tracer.value(value.clone()); + vm.engine.tracer.value(value.clone()); } Ok(value) } diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs index 7ccebe85..a57cb112 100644 --- a/crates/typst/src/eval/call.rs +++ b/crates/typst/src/eval/call.rs @@ -2,13 +2,13 @@ use comemo::{Prehashed, Tracked, TrackedMut}; use ecow::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::foundations::{ call_method_mut, is_mutating_method, Arg, Args, Bytes, Closure, Content, Func, IntoValue, NativeElement, Scope, Scopes, Value, }; use crate::introspection::{Introspector, Locator}; -use crate::layout::Vt; use crate::math::{Accent, AccentElem, LrElem}; use crate::symbols::Symbol; use crate::syntax::ast::{self, AstNode}; @@ -16,23 +16,19 @@ use crate::syntax::{Spanned, SyntaxNode}; use crate::text::TextElem; use crate::World; -/// The maxmium function call depth. -const MAX_CALL_DEPTH: usize = 64; - impl Eval for ast::FuncCall<'_> { type Output = Value; #[tracing::instrument(name = "FuncCall::eval", skip_all)] fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let span = self.span(); - if vm.depth >= MAX_CALL_DEPTH { - bail!(span, "maximum function call depth exceeded"); - } - let callee = self.callee(); let in_math = in_math(callee); let callee_span = callee.span(); let args = self.args(); + if vm.engine.route.exceeding() { + bail!(span, "maximum function call depth exceeded"); + } // Try to evaluate as a call to an associated function or field. let (callee, mut args) = if let ast::Expr::FieldAccess(access) = callee { @@ -146,7 +142,7 @@ impl Eval for ast::FuncCall<'_> { let callee = callee.cast::<Func>().at(callee_span)?; let point = || Tracepoint::Call(callee.name().map(Into::into)); - let f = || callee.call_vm(vm, args).trace(vm.world(), point, span); + let f = || callee.call(&mut vm.engine, args).trace(vm.world(), point, span); // Stacker is broken on WASM. #[cfg(target_arch = "wasm32")] @@ -229,7 +225,6 @@ impl Eval for ast::Closure<'_> { // Define the closure. let closure = Closure { node: self.to_untyped().clone(), - file: vm.file, defaults, captured, }; @@ -246,11 +241,10 @@ pub(crate) fn call_closure( func: &Func, closure: &Prehashed<Closure>, world: Tracked<dyn World + '_>, - route: Tracked<Route>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, - depth: usize, mut args: Args, ) -> SourceResult<Value> { let node = closure.node.cast::<ast::Closure>().unwrap(); @@ -260,13 +254,18 @@ pub(crate) fn call_closure( let mut scopes = Scopes::new(None); scopes.top = closure.captured.clone(); - // Prepare VT. + // Prepare the engine. let mut locator = Locator::chained(locator); - let vt = Vt { world, introspector, locator: &mut locator, tracer }; + let engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; // Prepare VM. - let mut vm = Vm::new(vt, route, closure.file, scopes); - vm.depth = depth; + let mut vm = Vm::new(engine, scopes, node.span()); // Provide the closure itself for recursive calls. if let Some(name) = node.name() { @@ -279,6 +278,7 @@ pub(crate) fn call_closure( .children() .filter(|p| matches!(p, ast::Param::Pos(_))) .count(); + let num_pos_args = args.to_pos().len(); let sink_size = num_pos_args.checked_sub(num_pos_params); diff --git a/crates/typst/src/eval/code.rs b/crates/typst/src/eval/code.rs index 1df5876c..06b2f226 100644 --- a/crates/typst/src/eval/code.rs +++ b/crates/typst/src/eval/code.rs @@ -40,7 +40,7 @@ fn eval_code<'a>( } let tail = eval_code(vm, exprs)?.display(); - Value::Content(tail.styled_with_recipe(vm, recipe)?) + Value::Content(tail.styled_with_recipe(&mut vm.engine, recipe)?) } _ => expr.eval(vm)?, }; @@ -130,7 +130,7 @@ impl Eval for ast::Expr<'_> { .spanned(span); if vm.inspected == Some(span) { - vm.vt.tracer.value(v.clone()); + vm.engine.tracer.value(v.clone()); } Ok(v) diff --git a/crates/typst/src/eval/import.rs b/crates/typst/src/eval/import.rs index 79daf999..aa3388a1 100644 --- a/crates/typst/src/eval/import.rs +++ b/crates/typst/src/eval/import.rs @@ -38,7 +38,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.vt.tracer.warn(warning!( + vm.engine.tracer.warn(warning!( new_name.span(), "unnecessary import rename to same name", )); @@ -73,7 +73,7 @@ impl Eval for ast::ModuleImport<'_> { if renamed_item.original_name().as_str() == renamed_item.new_name().as_str() { - vm.vt.tracer.warn(warning!( + vm.engine.tracer.warn(warning!( renamed_item.new_name().span(), "unnecessary import rename to same name", )); @@ -145,27 +145,37 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Mo let entrypoint_id = manifest_id.join(&manifest.package.entrypoint); let source = vm.world().source(entrypoint_id).at(span)?; let point = || Tracepoint::Import; - Ok(eval(vm.world(), vm.route, TrackedMut::reborrow_mut(&mut vm.vt.tracer), &source) - .trace(vm.world(), point, span)? - .with_name(manifest.package.name)) + Ok(eval( + vm.world(), + vm.engine.route.track(), + TrackedMut::reborrow_mut(&mut vm.engine.tracer), + &source, + ) + .trace(vm.world(), point, span)? + .with_name(manifest.package.name)) } /// Import a file from a path. fn import_file(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> { // Load the source file. let world = vm.world(); - let id = vm.resolve_path(path).at(span)?; + let id = span.resolve_path(path).at(span)?; let source = world.source(id).at(span)?; // Prevent cyclic importing. - if vm.route.contains(source.id()) { + if vm.engine.route.contains(source.id()) { bail!(span, "cyclic import"); } // Evaluate the file. let point = || Tracepoint::Import; - eval(world, vm.route, TrackedMut::reborrow_mut(&mut vm.vt.tracer), &source) - .trace(world, point, span) + eval( + world, + vm.engine.route.track(), + TrackedMut::reborrow_mut(&mut vm.engine.tracer), + &source, + ) + .trace(world, point, span) } /// A parsed package manifest. diff --git a/crates/typst/src/eval/markup.rs b/crates/typst/src/eval/markup.rs index 16ea9eef..a40b978e 100644 --- a/crates/typst/src/eval/markup.rs +++ b/crates/typst/src/eval/markup.rs @@ -43,7 +43,7 @@ fn eval_markup<'a>( } let tail = eval_markup(vm, exprs)?; - seq.push(tail.styled_with_recipe(vm, recipe)?) + seq.push(tail.styled_with_recipe(&mut vm.engine, recipe)?) } expr => match expr.eval(vm)? { Value::Label(label) => { @@ -139,11 +139,11 @@ impl Eval for ast::Strong<'_> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let body = self.body(); if body.exprs().next().is_none() { - vm.vt - .tracer - .warn(warning!(self.span(), "no text within stars").with_hint( + vm.engine.tracer.warn( + warning!(self.span(), "no text within stars").with_hint( "using multiple consecutive stars (e.g. **) has no additional effect", - )); + ), + ); } Ok(StrongElem::new(body.eval(vm)?).pack()) @@ -157,7 +157,7 @@ impl Eval for ast::Emph<'_> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let body = self.body(); if body.exprs().next().is_none() { - vm.vt + vm.engine .tracer .warn(warning!(self.span(), "no text within underscores").with_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 eaba69e0..9de4f1b7 100644 --- a/crates/typst/src/eval/mod.rs +++ b/crates/typst/src/eval/mod.rs @@ -26,9 +26,9 @@ pub(crate) use self::flow::*; use comemo::{Track, Tracked, TrackedMut}; use crate::diag::{bail, SourceResult}; +use crate::engine::{Engine, Route}; use crate::foundations::{Cast, Module, NativeElement, Scope, Scopes, Value}; use crate::introspection::{Introspector, Locator}; -use crate::layout::Vt; use crate::math::EquationElem; use crate::syntax::{ast, parse, parse_code, parse_math, Source, Span}; use crate::World; @@ -48,22 +48,23 @@ pub fn eval( panic!("Tried to cyclicly evaluate {:?}", id.vpath()); } - // Prepare VT. + // Prepare the engine. let mut locator = Locator::new(); let introspector = Introspector::default(); - let vt = Vt { + let engine = Engine { world, + route: Route::insert(route, id), introspector: introspector.track(), locator: &mut locator, tracer, }; // Prepare VM. - let route = Route::insert(route, id); + let root = source.root(); let scopes = Scopes::new(Some(world.library())); - let mut vm = Vm::new(vt, route.track(), Some(id), scopes); + let mut vm = Vm::new(engine, scopes, root.span()); - let root = source.root(); + // Check for well-formedness unless we are in trace mode. let errors = root.errors(); if !errors.is_empty() && vm.inspected.is_none() { return Err(errors.into_iter().map(Into::into).collect()); @@ -108,26 +109,27 @@ pub fn eval_string( root.synthesize(span); + // Check for well-formedness. let errors = root.errors(); if !errors.is_empty() { return Err(errors.into_iter().map(Into::into).collect()); } - // Prepare VT. + // Prepare the engine. let mut tracer = Tracer::new(); let mut locator = Locator::new(); let introspector = Introspector::default(); - let vt = Vt { + let engine = Engine { world, introspector: introspector.track(), + route: Route::default(), locator: &mut locator, tracer: tracer.track_mut(), }; // Prepare VM. - let route = Route::default(); let scopes = Scopes::new(Some(world.library())); - let mut vm = Vm::new(vt, route.track(), None, scopes); + let mut vm = Vm::new(engine, scopes, root.span()); vm.scopes.scopes.push(scope); // Evaluate the code. diff --git a/crates/typst/src/eval/rules.rs b/crates/typst/src/eval/rules.rs index c85b747b..e34fe5cd 100644 --- a/crates/typst/src/eval/rules.rs +++ b/crates/typst/src/eval/rules.rs @@ -24,7 +24,7 @@ impl Eval for ast::SetRule<'_> { }) .at(target.span())?; let args = self.args().eval(vm)?; - Ok(target.set(vm, args)?.spanned(self.span())) + Ok(target.set(&mut vm.engine, args)?.spanned(self.span())) } } diff --git a/crates/typst/src/eval/vm.rs b/crates/typst/src/eval/vm.rs index c34c1070..8cedb906 100644 --- a/crates/typst/src/eval/vm.rs +++ b/crates/typst/src/eval/vm.rs @@ -1,74 +1,37 @@ -use comemo::{Track, Tracked, Validate}; +use comemo::Tracked; -use crate::diag::{bail, StrResult}; +use crate::engine::Engine; use crate::eval::FlowEvent; use crate::foundations::{IntoValue, Scopes}; -use crate::layout::Vt; use crate::syntax::ast::{self, AstNode}; -use crate::syntax::{FileId, Span}; +use crate::syntax::Span; use crate::World; /// A virtual machine. /// -/// Holds the state needed to [evaluate](crate::eval::eval()) Typst sources. A new -/// virtual machine is created for each module evaluation and function call. +/// Holds the state needed to [evaluate](crate::eval::eval()) Typst sources. A +/// new virtual machine is created for each module evaluation and function call. pub struct Vm<'a> { /// The underlying virtual typesetter. - pub(crate) vt: Vt<'a>, - /// The route of source ids the VM took to reach its current location. - pub(crate) route: Tracked<'a, Route<'a>>, - /// The id of the currently evaluated file. - pub(crate) file: Option<FileId>, + pub(crate) engine: Engine<'a>, /// A control flow event that is currently happening. pub(crate) flow: Option<FlowEvent>, /// The stack of scopes. pub(crate) scopes: Scopes<'a>, - /// The current call depth. - pub(crate) depth: usize, /// A span that is currently under inspection. pub(crate) inspected: Option<Span>, } impl<'a> Vm<'a> { /// Create a new virtual machine. - pub fn new( - vt: Vt<'a>, - route: Tracked<'a, Route>, - file: Option<FileId>, - scopes: Scopes<'a>, - ) -> Self { - let inspected = file.and_then(|id| vt.tracer.inspected(id)); - Self { - vt, - route, - file, - flow: None, - scopes, - depth: 0, - inspected, - } + pub fn new(engine: Engine<'a>, scopes: Scopes<'a>, target: Span) -> Self { + let inspected = target.id().and_then(|id| engine.tracer.inspected(id)); + Self { engine, flow: None, scopes, inspected } } /// Access the underlying world. pub fn world(&self) -> Tracked<'a, dyn World + 'a> { - self.vt.world - } - - /// The id of the currently evaluated file. - /// - /// Returns `None` if the VM is in a detached context, e.g. when evaluating - /// a user-provided string. - pub fn file(&self) -> Option<FileId> { - self.file - } - - /// Resolve a path relative to the currently evaluated file. - pub fn resolve_path(&self, path: &str) -> StrResult<FileId> { - let Some(file) = self.file else { - bail!("cannot access file system from here"); - }; - - Ok(file.join(path)) + self.engine.world } /// Define a variable in the current scope. @@ -76,52 +39,8 @@ impl<'a> Vm<'a> { pub fn define(&mut self, var: ast::Ident, value: impl IntoValue) { let value = value.into_value(); if self.inspected == Some(var.span()) { - self.vt.tracer.value(value.clone()); + self.engine.tracer.value(value.clone()); } self.scopes.top.define(var.get().clone(), value); } } - -/// A route of source ids. -#[derive(Default)] -pub struct Route<'a> { - // We need to override the constraint's lifetime here so that `Tracked` is - // covariant over the constraint. If it becomes invariant, we're in for a - // world of lifetime pain. - outer: Option<Tracked<'a, Self, <Route<'static> as Validate>::Constraint>>, - id: Option<FileId>, -} - -impl<'a> Route<'a> { - /// Create a new route with just one entry. - pub fn new(id: Option<FileId>) -> Self { - Self { id, outer: None } - } - - /// Insert a new id into the route. - /// - /// You must guarantee that `outer` lives longer than the resulting - /// route is ever used. - pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self { - Route { outer: Some(outer), id: Some(id) } - } - - /// Start tracking this locator. - /// - /// In comparison to [`Track::track`], this method skips this chain link - /// if it does not contribute anything. - pub fn track(&self) -> Tracked<'_, Self> { - match self.outer { - Some(outer) if self.id.is_none() => outer, - _ => Track::track(self), - } - } -} - -#[comemo::track] -impl<'a> Route<'a> { - /// Whether the given id is part of the route. - pub fn contains(&self, id: FileId) -> bool { - self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id)) - } -} diff --git a/crates/typst/src/foundations/args.rs b/crates/typst/src/foundations/args.rs index af5d07b1..e11fe2bb 100644 --- a/crates/typst/src/foundations/args.rs +++ b/crates/typst/src/foundations/args.rs @@ -320,3 +320,26 @@ impl PartialEq for Arg { self.name == other.name && self.value.v == other.value.v } } + +/// Things that can be used as arguments. +pub trait IntoArgs { + /// Convert into arguments, attaching the `fallback` span in case `Self` + /// doesn't have a span. + fn into_args(self, fallback: Span) -> Args; +} + +impl IntoArgs for Args { + fn into_args(self, _: Span) -> Args { + self + } +} + +impl<I, T> IntoArgs for I +where + I: IntoIterator<Item = T>, + T: IntoValue, +{ + fn into_args(self, fallback: Span) -> Args { + Args::new(fallback, self) + } +} diff --git a/crates/typst/src/foundations/array.rs b/crates/typst/src/foundations/array.rs index 47afa9e2..8f2e9149 100644 --- a/crates/typst/src/foundations/array.rs +++ b/crates/typst/src/foundations/array.rs @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use crate::diag::{At, SourceResult, StrResult}; -use crate::eval::{ops, Vm}; +use crate::engine::Engine; +use crate::eval::ops; use crate::foundations::{ cast, func, repr, scope, ty, Args, Bytes, CastInfo, FromValue, Func, IntoValue, Reflect, Repr, Value, Version, @@ -297,14 +298,17 @@ impl Array { #[func] pub fn find( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. searcher: Func, ) -> SourceResult<Option<Value>> { for item in self.iter() { - let args = Args::new(searcher.span(), [item.clone()]); - if searcher.call_vm(vm, args)?.cast::<bool>().at(searcher.span())? { + if searcher + .call(engine, [item.clone()])? + .cast::<bool>() + .at(searcher.span())? + { return Ok(Some(item.clone())); } } @@ -316,14 +320,17 @@ impl Array { #[func] pub fn position( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. searcher: Func, ) -> SourceResult<Option<i64>> { for (i, item) in self.iter().enumerate() { - let args = Args::new(searcher.span(), [item.clone()]); - if searcher.call_vm(vm, args)?.cast::<bool>().at(searcher.span())? { + if searcher + .call(engine, [item.clone()])? + .cast::<bool>() + .at(searcher.span())? + { return Ok(Some(i as i64)); } } @@ -388,15 +395,14 @@ impl Array { #[func] pub fn filter( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<Array> { let mut kept = EcoVec::new(); for item in self.iter() { - let args = Args::new(test.span(), [item.clone()]); - if test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if test.call(engine, [item.clone()])?.cast::<bool>().at(test.span())? { kept.push(item.clone()) } } @@ -408,17 +414,12 @@ impl Array { #[func] pub fn map( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. mapper: Func, ) -> SourceResult<Array> { - self.into_iter() - .map(|item| { - let args = Args::new(mapper.span(), [item]); - mapper.call_vm(vm, args) - }) - .collect() + self.into_iter().map(|item| mapper.call(engine, [item])).collect() } /// Returns a new array with the values alongside their indices. @@ -518,8 +519,8 @@ impl Array { #[func] pub fn fold( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The initial value to start with. init: Value, /// The folding function. Must have two parameters: One for the @@ -528,8 +529,7 @@ impl Array { ) -> SourceResult<Value> { let mut acc = init; for item in self { - let args = Args::new(folder.span(), [acc, item]); - acc = folder.call_vm(vm, args)?; + acc = folder.call(engine, [acc, item])?; } Ok(acc) } @@ -579,14 +579,13 @@ impl Array { #[func] pub fn any( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<bool> { for item in self { - let args = Args::new(test.span(), [item]); - if test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if test.call(engine, [item])?.cast::<bool>().at(test.span())? { return Ok(true); } } @@ -598,14 +597,13 @@ impl Array { #[func] pub fn all( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<bool> { for item in self { - let args = Args::new(test.span(), [item]); - if !test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if !test.call(engine, [item])?.cast::<bool>().at(test.span())? { return Ok(false); } } @@ -714,8 +712,8 @@ impl Array { #[func] pub fn sorted( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The callsite span. span: Span, /// If given, applies this function to the elements in the array to @@ -728,7 +726,7 @@ impl Array { let mut key_of = |x: Value| match &key { // NOTE: We are relying on `comemo`'s memoization of function // evaluation to not excessively reevaluate the `key`. - Some(f) => f.call_vm(vm, Args::new(f.span(), [x])), + Some(f) => f.call(engine, [x]), None => Ok(x), }; vec.make_mut().sort_by(|a, b| { @@ -762,8 +760,8 @@ impl Array { #[func(title = "Deduplicate")] pub fn dedup( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// If given, applies this function to the elements in the array to /// determine the keys to deduplicate by. #[named] @@ -773,7 +771,7 @@ impl Array { let mut key_of = |x: Value| match &key { // NOTE: We are relying on `comemo`'s memoization of function // evaluation to not excessively reevaluate the `key`. - Some(f) => f.call_vm(vm, Args::new(f.span(), [x])), + Some(f) => f.call(engine, [x]), None => Ok(x), }; diff --git a/crates/typst/src/foundations/cast.rs b/crates/typst/src/foundations/cast.rs index fbd5ab14..e3b7dd01 100644 --- a/crates/typst/src/foundations/cast.rs +++ b/crates/typst/src/foundations/cast.rs @@ -12,6 +12,7 @@ use crate::diag::{At, SourceResult, StrResult}; use crate::foundations::{repr, Repr, Type, Value}; use crate::syntax::{Span, Spanned}; +#[rustfmt::skip] #[doc(inline)] pub use typst_macros::{cast, Cast}; diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs index 7a402629..111b33ea 100644 --- a/crates/typst/src/foundations/content.rs +++ b/crates/typst/src/foundations/content.rs @@ -10,7 +10,7 @@ use serde::{Serialize, Serializer}; use smallvec::smallvec; use crate::diag::{SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ elem, func, scope, ty, Dict, Element, FromValue, Guard, IntoValue, Label, NativeElement, Recipe, Repr, Selector, Str, Style, Styles, Value, @@ -299,16 +299,19 @@ impl Content { /// Access the child and styles. pub fn to_styled(&self) -> Option<(&Content, &Styles)> { let styled = self.to::<StyledElem>()?; - let child = styled.child(); let styles = styled.styles(); Some((child, styles)) } /// Style this content with a recipe, eagerly applying it if possible. - pub fn styled_with_recipe(self, vm: &mut Vm, recipe: Recipe) -> SourceResult<Self> { + pub fn styled_with_recipe( + self, + engine: &mut Engine, + recipe: Recipe, + ) -> SourceResult<Self> { if recipe.selector.is_none() { - recipe.apply_vm(vm, self) + recipe.apply(engine, self) } else { Ok(self.styled(recipe)) } diff --git a/crates/typst/src/foundations/datetime.rs b/crates/typst/src/foundations/datetime.rs index f50daf72..78290c99 100644 --- a/crates/typst/src/foundations/datetime.rs +++ b/crates/typst/src/foundations/datetime.rs @@ -8,7 +8,7 @@ use time::macros::format_description; use time::{format_description, Month, PrimitiveDateTime}; use crate::diag::{bail, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, func, repr, scope, ty, Dict, Duration, Repr, Smart, Str, Value, }; @@ -296,16 +296,15 @@ impl Datetime { /// ``` #[func] pub fn today( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// An offset to apply to the current UTC date. If set to `{auto}`, the /// offset will be the local offset. #[named] #[default] offset: Smart<i64>, ) -> StrResult<Datetime> { - Ok(vm - .vt + Ok(engine .world .today(offset.as_custom()) .ok_or("unable to get the current date")?) diff --git a/crates/typst/src/foundations/element.rs b/crates/typst/src/foundations/element.rs index 64b47b78..8e4d159a 100644 --- a/crates/typst/src/foundations/element.rs +++ b/crates/typst/src/foundations/element.rs @@ -10,13 +10,12 @@ use once_cell::sync::Lazy; use smallvec::SmallVec; use crate::diag::{SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, Args, Content, Dict, Func, Label, ParamInfo, Repr, Scope, Selector, StyleChain, Styles, Value, }; use crate::introspection::Location; -use crate::layout::Vt; use crate::syntax::Span; use crate::text::{Lang, Region}; use crate::util::Static; @@ -66,13 +65,17 @@ impl Element { } /// Construct an instance of this element. - pub fn construct(self, vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { - (self.0.construct)(vm, args) + pub fn construct( + self, + engine: &mut Engine, + args: &mut Args, + ) -> SourceResult<Content> { + (self.0.construct)(engine, args) } /// Execute the set rule for the element and return the resulting style map. - pub fn set(self, vm: &mut Vm, mut args: Args) -> SourceResult<Styles> { - let styles = (self.0.set)(vm, &mut args)?; + pub fn set(self, engine: &mut Engine, mut args: Args) -> SourceResult<Styles> { + let styles = (self.0.set)(engine, &mut args)?; args.finish()?; Ok(styles) } @@ -275,7 +278,7 @@ pub trait Construct { /// /// This is passed only the arguments that remain after execution of the /// element's set rule. - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> where Self: Sized; } @@ -283,7 +286,7 @@ pub trait Construct { /// An element's set rule. pub trait Set { /// Parse relevant arguments into style properties for this element. - fn set(vm: &mut Vm, args: &mut Args) -> SourceResult<Styles> + fn set(engine: &mut Engine, args: &mut Args) -> SourceResult<Styles> where Self: Sized; } @@ -295,8 +298,8 @@ pub struct NativeElementData { pub title: &'static str, pub docs: &'static str, pub keywords: &'static [&'static str], - pub construct: fn(&mut Vm, &mut Args) -> SourceResult<Content>, - pub set: fn(&mut Vm, &mut Args) -> SourceResult<Styles>, + pub construct: fn(&mut Engine, &mut Args) -> SourceResult<Content>, + pub set: fn(&mut Engine, &mut Args) -> SourceResult<Styles>, pub vtable: fn(of: TypeId) -> Option<*const ()>, pub field_id: fn(name: &str) -> Option<u8>, pub field_name: fn(u8) -> Option<&'static str>, @@ -320,13 +323,14 @@ cast! { /// rule. pub trait Synthesize { /// Prepare the element for show rule application. - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()>; + fn synthesize(&mut self, engine: &mut Engine, styles: StyleChain) + -> SourceResult<()>; } /// The base recipe for an element. pub trait Show { /// Execute the base recipe for this element. - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content>; + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content>; } /// Post-process an element after it was realized. diff --git a/crates/typst/src/foundations/func.rs b/crates/typst/src/foundations/func.rs index f1da6e37..6729b39d 100644 --- a/crates/typst/src/foundations/func.rs +++ b/crates/typst/src/foundations/func.rs @@ -6,14 +6,12 @@ use ecow::{eco_format, EcoString}; use once_cell::sync::Lazy; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::{Route, Vm}; +use crate::engine::Engine; use crate::foundations::{ - cast, repr, scope, ty, Args, CastInfo, Content, Element, IntoValue, Scope, Scopes, - Selector, Type, Value, + cast, repr, scope, ty, Args, CastInfo, Content, Element, IntoArgs, Scope, Selector, + Type, Value, }; -use crate::introspection::Locator; -use crate::layout::Vt; -use crate::syntax::{ast, FileId, Span, SyntaxNode}; +use crate::syntax::{ast, Span, SyntaxNode}; use crate::util::Static; #[doc(inline)] @@ -252,7 +250,13 @@ impl Func { } /// Call the function with the given arguments. - pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> { + #[tracing::instrument(skip_all)] + pub fn call(&self, engine: &mut Engine, args: impl IntoArgs) -> SourceResult<Value> { + self.call_impl(engine, args.into_args(self.span)) + } + + /// Non-generic implementation of `call`. + fn call_impl(&self, engine: &mut Engine, mut args: Args) -> SourceResult<Value> { let _span = tracing::info_span!( "call", name = self.name().unwrap_or("<anon>"), @@ -261,59 +265,32 @@ impl Func { match &self.repr { Repr::Native(native) => { - let value = (native.function)(vm, &mut args)?; + let value = (native.function)(engine, &mut args)?; args.finish()?; Ok(value) } Repr::Element(func) => { - let value = func.construct(vm, &mut args)?; + let value = func.construct(engine, &mut args)?; args.finish()?; Ok(Value::Content(value)) } - Repr::Closure(closure) => { - // Determine the route inside the closure. - let fresh = Route::new(closure.file); - let route = if vm.file.is_none() { fresh.track() } else { vm.route }; - crate::eval::call_closure( - self, - closure, - vm.world(), - route, - vm.vt.introspector, - vm.vt.locator.track(), - TrackedMut::reborrow_mut(&mut vm.vt.tracer), - vm.depth + 1, - args, - ) - } + Repr::Closure(closure) => crate::eval::call_closure( + self, + closure, + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), + args, + ), Repr::With(with) => { args.items = with.1.items.iter().cloned().chain(args.items).collect(); - with.0.call_vm(vm, args) + with.0.call(engine, args) } } } - /// Call the function with a Vt. - #[tracing::instrument(skip_all)] - pub fn call_vt<T: IntoValue>( - &self, - vt: &mut Vt, - args: impl IntoIterator<Item = T>, - ) -> SourceResult<Value> { - let route = Route::default(); - let scopes = Scopes::new(None); - let mut locator = Locator::chained(vt.locator.track()); - let vt = Vt { - world: vt.world, - introspector: vt.introspector, - locator: &mut locator, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), - }; - let mut vm = Vm::new(vt, route.track(), None, scopes); - let args = Args::new(self.span(), args); - self.call_vm(&mut vm, args) - } - /// The function's span. pub fn span(&self) -> Span { self.span @@ -443,7 +420,7 @@ pub trait NativeFunc { /// Defines a native function. #[derive(Debug)] pub struct NativeFuncData { - pub function: fn(&mut Vm, &mut Args) -> SourceResult<Value>, + pub function: fn(&mut Engine, &mut Args) -> SourceResult<Value>, pub name: &'static str, pub title: &'static str, pub docs: &'static str, @@ -495,8 +472,6 @@ pub struct ParamInfo { pub struct Closure { /// The closure's syntax node. Must be castable to `ast::Closure`. pub node: SyntaxNode, - /// The source file where the closure was defined. - pub file: Option<FileId>, /// Default values of named parameters. pub defaults: Vec<Value>, /// Captured values from outer scopes. diff --git a/crates/typst/src/foundations/mod.rs b/crates/typst/src/foundations/mod.rs index b2c35194..4ddc2162 100644 --- a/crates/typst/src/foundations/mod.rs +++ b/crates/typst/src/foundations/mod.rs @@ -60,6 +60,7 @@ pub use self::ty::*; pub use self::value::*; pub use self::version::*; +#[rustfmt::skip] #[doc(hidden)] pub use { ecow::{eco_format, eco_vec}, @@ -70,7 +71,8 @@ pub use { use ecow::EcoString; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::{EvalMode, Vm}; +use crate::engine::Engine; +use crate::eval::EvalMode; use crate::syntax::Spanned; /// Foundational types and functions. @@ -251,8 +253,8 @@ impl assert { /// ``` #[func(title = "Evaluate")] pub fn eval( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// A string of Typst code to evaluate. /// /// The code in the string cannot interact with the file system. @@ -289,5 +291,5 @@ pub fn eval( for (key, value) in dict { scope.define(key, value); } - crate::eval::eval_string(vm.world(), &text, span, mode, scope) + crate::eval::eval_string(engine.world, &text, span, mode, scope) } diff --git a/crates/typst/src/foundations/plugin.rs b/crates/typst/src/foundations/plugin.rs index 6071b3bd..89237f94 100644 --- a/crates/typst/src/foundations/plugin.rs +++ b/crates/typst/src/foundations/plugin.rs @@ -3,10 +3,10 @@ use std::hash::{Hash, Hasher}; use std::sync::{Arc, Mutex}; use ecow::{eco_format, EcoString}; -use wasmi::{AsContext, AsContextMut, Caller, Engine, Linker, Module}; +use wasmi::{AsContext, AsContextMut}; use crate::diag::{bail, At, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, repr, scope, ty, Bytes}; use crate::syntax::Spanned; use crate::World; @@ -152,14 +152,14 @@ impl Plugin { /// Creates a new plugin from a WebAssembly file. #[func(constructor)] pub fn construct( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a WebAssembly file. path: Spanned<EcoString>, ) -> SourceResult<Plugin> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; Plugin::new(data).at(span) } } @@ -168,11 +168,11 @@ impl Plugin { /// Create a new plugin from raw WebAssembly bytes. #[comemo::memoize] pub fn new(bytes: Bytes) -> StrResult<Self> { - let engine = Engine::default(); - let module = Module::new(&engine, bytes.as_slice()) + let engine = wasmi::Engine::default(); + let module = wasmi::Module::new(&engine, bytes.as_slice()) .map_err(|err| format!("failed to load WebAssembly module ({err})"))?; - let mut linker = Linker::new(&engine); + let mut linker = wasmi::Linker::new(&engine); linker .func_wrap( "typst_env", @@ -323,7 +323,10 @@ impl Hash for Plugin { } /// Write the arguments to the plugin function into the plugin's memory. -fn wasm_minimal_protocol_write_args_to_buffer(mut caller: Caller<StoreData>, ptr: u32) { +fn wasm_minimal_protocol_write_args_to_buffer( + mut caller: wasmi::Caller<StoreData>, + ptr: u32, +) { let memory = caller.get_export("memory").unwrap().into_memory().unwrap(); let arguments = std::mem::take(&mut caller.data_mut().args); let mut offset = ptr as usize; @@ -342,7 +345,7 @@ fn wasm_minimal_protocol_write_args_to_buffer(mut caller: Caller<StoreData>, ptr /// Extracts the output of the plugin function from the plugin's memory. fn wasm_minimal_protocol_send_result_to_host( - mut caller: Caller<StoreData>, + mut caller: wasmi::Caller<StoreData>, ptr: u32, len: u32, ) { diff --git a/crates/typst/src/foundations/str.rs b/crates/typst/src/foundations/str.rs index 4b56971a..83bde675 100644 --- a/crates/typst/src/foundations/str.rs +++ b/crates/typst/src/foundations/str.rs @@ -8,10 +8,10 @@ use serde::{Deserialize, Serialize}; use unicode_segmentation::UnicodeSegmentation; use crate::diag::{bail, At, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ - cast, dict, func, repr, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Label, - Repr, Type, Value, Version, + cast, dict, func, repr, scope, ty, Array, Bytes, Dict, Func, IntoValue, Label, Repr, + Type, Value, Version, }; use crate::layout::Align; use crate::syntax::{Span, Spanned}; @@ -422,8 +422,8 @@ impl Str { #[func] pub fn replace( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The pattern to search for. pattern: StrPattern, /// The string to replace the matches with or a function that gets a @@ -449,8 +449,8 @@ impl Str { match &replacement { Replacement::Str(s) => output.push_str(s), Replacement::Func(func) => { - let args = Args::new(func.span(), [dict.into_value()]); - let piece = func.call_vm(vm, args)?.cast::<Str>().at(func.span())?; + let piece = + func.call(engine, [dict])?.cast::<Str>().at(func.span())?; output.push_str(&piece); } } diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs index 78bd24d6..ca6a9e78 100644 --- a/crates/typst/src/foundations/styles.rs +++ b/crates/typst/src/foundations/styles.rs @@ -10,12 +10,10 @@ use once_cell::sync::Lazy; use smallvec::SmallVec; use crate::diag::{SourceResult, Trace, Tracepoint}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ - cast, elem, func, ty, Args, Content, Element, Func, NativeElement, Repr, Selector, - Show, Value, + cast, elem, func, ty, Content, Element, Func, NativeElement, Repr, Selector, Show, }; -use crate::layout::Vt; use crate::syntax::Span; use crate::text::{FontFamily, FontList, TextElem}; @@ -58,8 +56,8 @@ struct StyleElem { impl Show for StyleElem { #[tracing::instrument(name = "StyleElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.func().call_vt(vt, [styles.to_map()])?.display()) + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(self.func().call(engine, [styles.to_map()])?.display()) } } @@ -356,37 +354,23 @@ impl Recipe { } /// Apply the recipe to the given content. - pub fn apply_vm(&self, vm: &mut Vm, content: Content) -> SourceResult<Content> { - match &self.transform { - Transformation::Content(content) => Ok(content.clone()), + pub fn apply(&self, engine: &mut Engine, content: Content) -> SourceResult<Content> { + let mut content = match &self.transform { + Transformation::Content(content) => content.clone(), Transformation::Func(func) => { - let args = Args::new(self.span, [Value::Content(content.clone())]); - let mut result = func.call_vm(vm, args); - // For selector-less show rules, a tracepoint makes no sense. + let mut result = func.call(engine, [content.clone()]); if self.selector.is_some() { let point = || Tracepoint::Show(content.func().name().into()); - result = result.trace(vm.world(), point, content.span()); + result = result.trace(engine.world, point, content.span()); } - Ok(result?.display()) + result?.display() } - Transformation::Style(styles) => Ok(content.styled_with_map(styles.clone())), - } - } - - /// Apply the recipe to the given content. - pub fn apply_vt(&self, vt: &mut Vt, content: Content) -> SourceResult<Content> { - match &self.transform { - Transformation::Content(content) => Ok(content.clone()), - Transformation::Func(func) => { - let mut result = func.call_vt(vt, [Value::Content(content.clone())]); - if self.selector.is_some() { - let point = || Tracepoint::Show(content.func().name().into()); - result = result.trace(vt.world, point, content.span()); - } - Ok(result?.display()) - } - Transformation::Style(styles) => Ok(content.styled_with_map(styles.clone())), + Transformation::Style(styles) => content.styled_with_map(styles.clone()), + }; + if content.span().is_detached() { + content = content.spanned(self.span); } + Ok(content) } } diff --git a/crates/typst/src/foundations/ty.rs b/crates/typst/src/foundations/ty.rs index 47add6ec..4c2098f3 100644 --- a/crates/typst/src/foundations/ty.rs +++ b/crates/typst/src/foundations/ty.rs @@ -8,6 +8,7 @@ use crate::diag::StrResult; use crate::foundations::{cast, func, Func, NativeFuncData, Repr, Scope, Value}; use crate::util::Static; +#[rustfmt::skip] #[doc(inline)] pub use typst_macros::{scope, ty}; diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs index 7b073681..ce485997 100644 --- a/crates/typst/src/introspection/counter.rs +++ b/crates/typst/src/introspection/counter.rs @@ -6,6 +6,7 @@ use ecow::{eco_format, eco_vec, EcoString, EcoVec}; use smallvec::{smallvec, SmallVec}; use crate::diag::{At, SourceResult, StrResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Array, Content, Element, Func, IntoValue, @@ -13,7 +14,7 @@ use crate::foundations::{ Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator, Meta}; -use crate::layout::{Frame, FrameItem, PageElem, Vt}; +use crate::layout::{Frame, FrameItem, PageElem}; use crate::math::EquationElem; use crate::model::{FigureElem, HeadingElem, Numbering, NumberingPattern}; use crate::util::NonZeroExt; @@ -222,9 +223,13 @@ impl Counter { } /// Gets the current and final value of the state combined in one state. - pub fn both(&self, vt: &mut Vt, location: Location) -> SourceResult<CounterState> { - let sequence = self.sequence(vt)?; - let offset = vt + pub fn both( + &self, + engine: &mut Engine, + location: Location, + ) -> SourceResult<CounterState> { + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); @@ -232,10 +237,10 @@ impl Counter { let (mut final_state, final_page) = sequence.last().unwrap().clone(); if self.is_page() { let at_delta = - vt.introspector.page(location).get().saturating_sub(at_page.get()); + engine.introspector.page(location).get().saturating_sub(at_page.get()); at_state.step(NonZeroUsize::ONE, at_delta); let final_delta = - vt.introspector.pages().get().saturating_sub(final_page.get()); + engine.introspector.pages().get().saturating_sub(final_page.get()); final_state.step(NonZeroUsize::ONE, final_delta); } Ok(CounterState(smallvec![at_state.first(), final_state.first()])) @@ -247,13 +252,14 @@ impl Counter { /// of counter updates from quadratic to linear. fn sequence( &self, - vt: &mut Vt, + engine: &mut Engine, ) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> { self.sequence_impl( - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), ) } @@ -263,11 +269,18 @@ impl Counter { &self, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, ) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let mut state = CounterState::init(&self.0); let mut page = NonZeroUsize::ONE; @@ -288,7 +301,7 @@ impl Counter { Some(countable) => countable.update(), None => Some(CounterUpdate::Step(NonZeroUsize::ONE)), } { - state.update(&mut vt, update)?; + state.update(&mut engine, update)?; } stops.push((state.clone(), page)); @@ -399,21 +412,22 @@ impl Counter { #[func] pub fn at( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// The location at which the counter value should be retrieved. A /// suitable location can be retrieved from [`locate`]($locate) or /// [`query`]($query). location: Location, ) -> SourceResult<CounterState> { - let sequence = self.sequence(vt)?; - let offset = vt + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); let (mut state, page) = sequence[offset].clone(); if self.is_page() { - let delta = vt.introspector.page(location).get().saturating_sub(page.get()); + let delta = + engine.introspector.page(location).get().saturating_sub(page.get()); state.step(NonZeroUsize::ONE, delta); } @@ -425,8 +439,8 @@ impl Counter { #[func] pub fn final_( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// Can be an arbitrary location, as its value is irrelevant for the /// method's return value. Why is it required then? Typst has to /// evaluate parts of your code multiple times to determine all counter @@ -438,10 +452,10 @@ impl Counter { location: Location, ) -> SourceResult<CounterState> { let _ = location; - let sequence = self.sequence(vt)?; + let sequence = self.sequence(engine)?; let (mut state, page) = sequence.last().unwrap().clone(); if self.is_page() { - let delta = vt.introspector.pages().get().saturating_sub(page.get()); + let delta = engine.introspector.pages().get().saturating_sub(page.get()); state.step(NonZeroUsize::ONE, delta); } Ok(state) @@ -544,12 +558,17 @@ impl CounterState { } /// Advance the counter and return the numbers for the given heading. - pub fn update(&mut self, vt: &mut Vt, update: CounterUpdate) -> SourceResult<()> { + pub fn update( + &mut self, + engine: &mut Engine, + update: CounterUpdate, + ) -> SourceResult<()> { match update { CounterUpdate::Set(state) => *self = state, CounterUpdate::Step(level) => self.step(level, 1), CounterUpdate::Func(func) => { - *self = func.call_vt(vt, self.0.iter().copied())?.cast().at(func.span())? + *self = + func.call(engine, self.0.iter().copied())?.cast().at(func.span())? } } Ok(()) @@ -575,8 +594,12 @@ impl CounterState { } /// Display the counter state with a numbering. - pub fn display(&self, vt: &mut Vt, numbering: &Numbering) -> SourceResult<Content> { - Ok(numbering.apply_vt(vt, &self.0)?.display()) + pub fn display( + &self, + engine: &mut Engine, + numbering: &Numbering, + ) -> SourceResult<Content> { + Ok(numbering.apply(engine, &self.0)?.display()) } } @@ -608,8 +631,8 @@ struct DisplayElem { impl Show for DisplayElem { #[tracing::instrument(name = "DisplayElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); let counter = self.counter(); let numbering = self @@ -633,12 +656,12 @@ impl Show for DisplayElem { .unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into()); let state = if *self.both() { - counter.both(vt, location)? + counter.both(engine, location)? } else { - counter.at(vt, location)? + counter.at(engine, location)? }; - state.display(vt, &numbering) + state.display(engine, &numbering) })) } } @@ -657,7 +680,7 @@ struct UpdateElem { impl Show for UpdateElem { #[tracing::instrument(name = "UpdateElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } @@ -693,15 +716,15 @@ impl ManualPageCounter { } /// Advance past a page. - pub fn visit(&mut self, vt: &mut Vt, page: &Frame) -> SourceResult<()> { + pub fn visit(&mut self, engine: &mut Engine, page: &Frame) -> SourceResult<()> { for (_, item) in page.items() { match item { - FrameItem::Group(group) => self.visit(vt, &group.frame)?, + FrameItem::Group(group) => self.visit(engine, &group.frame)?, FrameItem::Meta(Meta::Elem(elem), _) => { let Some(elem) = elem.to::<UpdateElem>() else { continue }; if *elem.key() == CounterKey::Page { let mut state = CounterState(smallvec![self.logical]); - state.update(vt, elem.update().clone())?; + state.update(engine, elem.update().clone())?; self.logical = state.first(); } } diff --git a/crates/typst/src/introspection/locate.rs b/crates/typst/src/introspection/locate.rs index 1c4f0e5a..69dcadd8 100644 --- a/crates/typst/src/introspection/locate.rs +++ b/crates/typst/src/introspection/locate.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, func, Content, Func, NativeElement, Show, StyleChain}; use crate::introspection::Locatable; -use crate::layout::Vt; /// Provides access to the location of content. /// @@ -37,11 +37,11 @@ struct LocateElem { } impl Show for LocateElem { - #[tracing::instrument(name = "LocateElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "LocateElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); - Ok(self.func().call_vt(vt, [location])?.display()) + Ok(self.func().call(engine, [location])?.display()) })) } } diff --git a/crates/typst/src/introspection/location.rs b/crates/typst/src/introspection/location.rs index b70dc4ad..0ceaac8b 100644 --- a/crates/typst/src/introspection/location.rs +++ b/crates/typst/src/introspection/location.rs @@ -2,7 +2,7 @@ use std::num::NonZeroUsize; use ecow::EcoString; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{cast, func, scope, ty, Dict, Repr}; use crate::model::Numbering; @@ -45,8 +45,8 @@ impl Location { /// If you want to know the value of the page counter, use /// `{counter(page).at(loc)}` instead. #[func] - pub fn page(self, vm: &mut Vm) -> NonZeroUsize { - vm.vt.introspector.page(self) + pub fn page(self, engine: &mut Engine) -> NonZeroUsize { + engine.introspector.page(self) } /// Return a dictionary with the page number and the x, y position for this @@ -56,8 +56,8 @@ impl Location { /// If you only need the page number, use `page()` instead as it allows /// Typst to skip unnecessary work. #[func] - pub fn position(self, vm: &mut Vm) -> Dict { - vm.vt.introspector.position(self).into() + pub fn position(self, engine: &mut Engine) -> Dict { + engine.introspector.position(self).into() } /// Returns the page numbering pattern of the page at this location. This @@ -68,8 +68,8 @@ impl Location { /// If the page numbering is set to `none` at that location, this function /// returns `none`. #[func] - pub fn page_numbering(self, vm: &mut Vm) -> Option<Numbering> { - vm.vt.introspector.page_numbering(self).cloned() + pub fn page_numbering(self, engine: &mut Engine) -> Option<Numbering> { + engine.introspector.page_numbering(self).cloned() } } @@ -83,5 +83,5 @@ cast! { type Location, } -/// Makes this element locatable through `vt.locate`. +/// Makes this element locatable through `engine.locate`. pub trait Locatable {} diff --git a/crates/typst/src/introspection/metadata.rs b/crates/typst/src/introspection/metadata.rs index 4042bc04..15d144eb 100644 --- a/crates/typst/src/introspection/metadata.rs +++ b/crates/typst/src/introspection/metadata.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Behave, Behaviour, Content, Show, StyleChain, Value}; use crate::introspection::Locatable; -use crate::layout::Vt; /// Exposes a value to the query system without producing visible content. /// @@ -31,7 +31,7 @@ pub struct MetadataElem { } impl Show for MetadataElem { - fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } diff --git a/crates/typst/src/introspection/query.rs b/crates/typst/src/introspection/query.rs index 1024238e..5b70ba51 100644 --- a/crates/typst/src/introspection/query.rs +++ b/crates/typst/src/introspection/query.rs @@ -1,4 +1,4 @@ -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, Array, LocatableSelector, Value}; use crate::introspection::Location; @@ -129,8 +129,8 @@ use crate::introspection::Location; /// ``` #[func] pub fn query( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Can be an element function like a `heading` or `figure`, a `{<label>}` /// or a more complex selector like `{heading.where(level: 1)}`. /// @@ -152,7 +152,7 @@ pub fn query( location: Location, ) -> Array { let _ = location; - let vec = vm.vt.introspector.query(&target.0); + let vec = engine.introspector.query(&target.0); vec.into_iter() .map(|elem| Value::Content(elem.into_inner())) .collect() diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs index af6d7933..8479bace 100644 --- a/crates/typst/src/introspection/state.rs +++ b/crates/typst/src/introspection/state.rs @@ -2,13 +2,13 @@ use comemo::{Tracked, TrackedMut}; use ecow::{eco_format, eco_vec, EcoString, EcoVec}; use crate::diag::SourceResult; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Repr, Selector, Show, Str, StyleChain, Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator}; -use crate::layout::Vt; use crate::World; /// Manages stateful parts of your document. @@ -204,12 +204,13 @@ impl State { /// /// This has to happen just once for all states, cutting down the number /// of state updates from quadratic to linear. - fn sequence(&self, vt: &mut Vt) -> SourceResult<EcoVec<Value>> { + fn sequence(&self, engine: &mut Engine) -> SourceResult<EcoVec<Value>> { self.sequence_impl( - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), ) } @@ -219,11 +220,18 @@ impl State { &self, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, ) -> SourceResult<EcoVec<Value>> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let mut state = self.init.clone(); let mut stops = eco_vec![state.clone()]; @@ -231,7 +239,7 @@ impl State { let elem = elem.to::<UpdateElem>().unwrap(); match elem.update() { StateUpdate::Set(value) => state = value.clone(), - StateUpdate::Func(func) => state = func.call_vt(&mut vt, [state])?, + StateUpdate::Func(func) => state = func.call(&mut engine, [state])?, } stops.push(state.clone()); } @@ -295,15 +303,15 @@ impl State { #[func] pub fn at( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// The location at which the state's value should be retrieved. A /// suitable location can be retrieved from [`locate`]($locate) or /// [`query`]($query). location: Location, ) -> SourceResult<Value> { - let sequence = self.sequence(vt)?; - let offset = vt + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); @@ -314,8 +322,8 @@ impl State { #[func] pub fn final_( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// Can be an arbitrary location, as its value is irrelevant for the /// method's return value. Why is it required then? As noted before, /// Typst has to evaluate parts of your code multiple times to determine @@ -327,7 +335,7 @@ impl State { location: Location, ) -> SourceResult<Value> { let _ = location; - let sequence = self.sequence(vt)?; + let sequence = self.sequence(engine)?; Ok(sequence.last().unwrap().clone()) } } @@ -377,13 +385,13 @@ struct DisplayElem { } impl Show for DisplayElem { - #[tracing::instrument(name = "DisplayElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "DisplayElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); - let value = self.state().at(vt, location)?; + let value = self.state().at(engine, location)?; Ok(match self.func() { - Some(func) => func.call_vt(vt, [value])?.display(), + Some(func) => func.call(engine, [value])?.display(), None => value.display(), }) })) @@ -404,7 +412,7 @@ struct UpdateElem { impl Show for UpdateElem { #[tracing::instrument(name = "UpdateElem::show")] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs index 74db4373..3d4017f3 100644 --- a/crates/typst/src/layout/align.rs +++ b/crates/typst/src/layout/align.rs @@ -3,10 +3,11 @@ use std::ops::Add; use ecow::{eco_format, EcoString}; use crate::diag::{bail, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, func, scope, ty, Content, Fold, Repr, Resolve, Show, StyleChain, }; -use crate::layout::{Abs, Axes, Axis, Dir, Side, Vt}; +use crate::layout::{Abs, Axes, Axis, Dir, Side}; use crate::text::TextElem; /// Aligns content horizontally and vertically. @@ -46,7 +47,7 @@ pub struct AlignElem { impl Show for AlignElem { #[tracing::instrument(name = "AlignElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() .clone() diff --git a/crates/typst/src/layout/columns.rs b/crates/typst/src/layout/columns.rs index 852ef8f8..275dbbeb 100644 --- a/crates/typst/src/layout/columns.rs +++ b/crates/typst/src/layout/columns.rs @@ -1,9 +1,10 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Behave, Behaviour, Content, StyleChain}; use crate::layout::{ - Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size, Vt, + Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size, }; use crate::text::TextElem; use crate::util::Numeric; @@ -60,7 +61,7 @@ impl Layout for ColumnsElem { #[tracing::instrument(name = "ColumnsElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -69,7 +70,7 @@ impl Layout for ColumnsElem { // Separating the infinite space into infinite columns does not make // much sense. if !regions.size.x.is_finite() { - return body.layout(vt, styles, regions); + return body.layout(engine, styles, regions); } // Determine the width of the gutter and each column. @@ -94,7 +95,7 @@ impl Layout for ColumnsElem { }; // Layout the children. - let mut frames = body.layout(vt, styles, pod)?.into_iter(); + let mut frames = body.layout(engine, styles, pod)?.into_iter(); let mut finished = vec![]; let dir = TextElem::dir_in(styles); diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs index cb65d4d8..cdc5c489 100644 --- a/crates/typst/src/layout/container.rs +++ b/crates/typst/src/layout/container.rs @@ -1,10 +1,11 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, AutoValue, Content, NativeElement, Resolve, Smart, StyleChain, Value, }; use crate::layout::{ Abs, Axes, Corners, Em, Fr, Fragment, FrameKind, Layout, Length, Ratio, Regions, Rel, - Sides, Size, Spacing, VElem, Vt, + Sides, Size, Spacing, VElem, }; use crate::util::Numeric; use crate::visualize::{clip_rect, Paint, Stroke}; @@ -112,7 +113,7 @@ impl Layout for BoxElem { #[tracing::instrument(name = "BoxElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -140,7 +141,7 @@ impl Layout for BoxElem { // Select the appropriate base and expansion for the child depending // on whether it is automatically or relatively sized. let pod = Regions::one(size, expand); - let mut frame = body.layout(vt, styles, pod)?.into_frame(); + let mut frame = body.layout(engine, styles, pod)?.into_frame(); // Enforce correct size. *frame.size_mut() = expand.select(size, frame.size()); @@ -344,7 +345,7 @@ impl Layout for BlockElem { #[tracing::instrument(name = "BlockElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -368,7 +369,7 @@ impl Layout for BlockElem { // Measure to ensure frames for all regions have the same width. if sizing.x == Smart::Auto { let pod = Regions::one(size, Axes::splat(false)); - let frame = body.measure(vt, styles, pod)?.into_frame(); + let frame = body.measure(engine, styles, pod)?.into_frame(); size.x = frame.width(); expand.x = true; } @@ -403,7 +404,7 @@ impl Layout for BlockElem { pod.last = None; } - let mut frames = body.layout(vt, styles, pod)?.into_frames(); + let mut frames = body.layout(engine, styles, pod)?.into_frames(); for (frame, &height) in frames.iter_mut().zip(&heights) { *frame.size_mut() = expand.select(Size::new(size.x, height), frame.size()); @@ -411,7 +412,7 @@ impl Layout for BlockElem { frames } else { let pod = Regions::one(size, expand); - let mut frames = body.layout(vt, styles, pod)?.into_frames(); + let mut frames = body.layout(engine, styles, pod)?.into_frames(); *frames[0].size_mut() = expand.select(size, frames[0].size()); frames }; diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs index 1c97c110..b4e7afd1 100644 --- a/crates/typst/src/layout/flow.rs +++ b/crates/typst/src/layout/flow.rs @@ -1,12 +1,13 @@ use comemo::Prehashed; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; use crate::introspection::{Meta, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BlockElem, ColbreakElem, ColumnsElem, FixedAlign, Fr, Fragment, Frame, FrameItem, Layout, PlaceElem, Point, Regions, Rel, Size, Spacing, VAlign, - VElem, Vt, + VElem, }; use crate::model::{FootnoteElem, FootnoteEntry, ParElem}; use crate::util::Numeric; @@ -30,7 +31,7 @@ impl Layout for FlowElem { #[tracing::instrument(name = "FlowElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -51,9 +52,9 @@ impl Layout for FlowElem { } if let Some(elem) = child.to::<VElem>() { - layouter.layout_spacing(vt, elem, styles)?; + layouter.layout_spacing(engine, elem, styles)?; } else if let Some(elem) = child.to::<ParElem>() { - layouter.layout_par(vt, elem, styles)?; + layouter.layout_par(engine, elem, styles)?; } else if child.is::<LineElem>() || child.is::<RectElem>() || child.is::<SquareElem>() @@ -64,7 +65,7 @@ impl Layout for FlowElem { || child.is::<PathElem>() { let layoutable = child.with::<dyn Layout>().unwrap(); - layouter.layout_single(vt, layoutable, styles)?; + layouter.layout_single(engine, layoutable, styles)?; } else if child.is::<MetaElem>() { let mut frame = Frame::soft(Size::zero()); frame.meta(styles, true); @@ -75,20 +76,20 @@ impl Layout for FlowElem { movable: false, }); } else if let Some(placed) = child.to::<PlaceElem>() { - layouter.layout_placed(vt, placed, styles)?; + layouter.layout_placed(engine, placed, styles)?; } else if child.can::<dyn Layout>() { - layouter.layout_multiple(vt, child, styles)?; + layouter.layout_multiple(engine, child, styles)?; } else if child.is::<ColbreakElem>() { if !layouter.regions.backlog.is_empty() || layouter.regions.last.is_some() { - layouter.finish_region(vt)?; + layouter.finish_region(engine)?; } } else { bail!(child.span(), "unexpected flow child"); } } - layouter.finish(vt) + layouter.finish(engine) } } @@ -193,12 +194,12 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_spacing", skip_all)] fn layout_spacing( &mut self, - vt: &mut Vt, + engine: &mut Engine, v: &VElem, styles: StyleChain, ) -> SourceResult<()> { self.layout_item( - vt, + engine, match v.amount() { Spacing::Rel(rel) => FlowItem::Absolute( rel.resolve(styles).relative_to(self.initial.y), @@ -213,7 +214,7 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_par", skip_all)] fn layout_par( &mut self, - vt: &mut Vt, + engine: &mut Engine, par: &ParElem, styles: StyleChain, ) -> SourceResult<()> { @@ -221,7 +222,13 @@ impl<'a> FlowLayouter<'a> { let leading = ParElem::leading_in(styles); let consecutive = self.last_was_par; let lines = par - .layout(vt, styles, consecutive, self.regions.base(), self.regions.expand.x)? + .layout( + engine, + styles, + consecutive, + self.regions.base(), + self.regions.expand.x, + )? .into_frames(); let mut sticky = self.items.len(); @@ -236,20 +243,20 @@ impl<'a> FlowLayouter<'a> { if let Some(first) = lines.first() { if !self.regions.size.y.fits(first.height()) && !self.regions.in_last() { let carry: Vec<_> = self.items.drain(sticky..).collect(); - self.finish_region(vt)?; + self.finish_region(engine)?; for item in carry { - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } } } for (i, frame) in lines.into_iter().enumerate() { if i > 0 { - self.layout_item(vt, FlowItem::Absolute(leading, true))?; + self.layout_item(engine, FlowItem::Absolute(leading, true))?; } self.layout_item( - vt, + engine, FlowItem::Frame { frame, align, sticky: false, movable: true }, )?; } @@ -262,15 +269,18 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_single", skip_all)] fn layout_single( &mut self, - vt: &mut Vt, + engine: &mut Engine, content: &dyn Layout, styles: StyleChain, ) -> SourceResult<()> { let align = AlignElem::alignment_in(styles).resolve(styles); let sticky = BlockElem::sticky_in(styles); let pod = Regions::one(self.regions.base(), Axes::splat(false)); - let frame = content.layout(vt, styles, pod)?.into_frame(); - self.layout_item(vt, FlowItem::Frame { frame, align, sticky, movable: true })?; + let frame = content.layout(engine, styles, pod)?.into_frame(); + self.layout_item( + engine, + FlowItem::Frame { frame, align, sticky, movable: true }, + )?; self.last_was_par = false; Ok(()) } @@ -278,7 +288,7 @@ impl<'a> FlowLayouter<'a> { /// Layout a placed element. fn layout_placed( &mut self, - vt: &mut Vt, + engine: &mut Engine, placed: &PlaceElem, styles: StyleChain, ) -> SourceResult<()> { @@ -290,15 +300,15 @@ impl<'a> FlowLayouter<'a> { align.x().unwrap_or_default().resolve(styles) }); let y_align = alignment.map(|align| align.y().map(VAlign::fix)); - let frame = placed.layout(vt, styles, self.regions)?.into_frame(); + let frame = placed.layout(engine, styles, self.regions)?.into_frame(); let item = FlowItem::Placed { frame, x_align, y_align, delta, float, clearance }; - self.layout_item(vt, item) + self.layout_item(engine, item) } /// Layout into multiple regions. fn layout_multiple( &mut self, - vt: &mut Vt, + engine: &mut Engine, block: &Content, styles: StyleChain, ) -> SourceResult<()> { @@ -313,7 +323,7 @@ impl<'a> FlowLayouter<'a> { if self.regions.is_full() { // Skip directly if region is already full. - self.finish_region(vt)?; + self.finish_region(engine)?; } // How to align the block. @@ -328,7 +338,7 @@ impl<'a> FlowLayouter<'a> { // Layout the block itself. let sticky = BlockElem::sticky_in(styles); - let fragment = block.layout(vt, styles, self.regions)?; + let fragment = block.layout(engine, styles, self.regions)?; for (i, frame) in fragment.into_iter().enumerate() { // Find footnotes in the frame. @@ -337,14 +347,14 @@ impl<'a> FlowLayouter<'a> { } if i > 0 { - self.finish_region(vt)?; + self.finish_region(engine)?; } let item = FlowItem::Frame { frame, align, sticky, movable: false }; - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } - self.try_handle_footnotes(vt, notes)?; + self.try_handle_footnotes(engine, notes)?; self.root = is_root; self.regions.root = false; @@ -355,7 +365,11 @@ impl<'a> FlowLayouter<'a> { /// Layout a finished frame. #[tracing::instrument(name = "FlowLayouter::layout_item", skip_all)] - fn layout_item(&mut self, vt: &mut Vt, mut item: FlowItem) -> SourceResult<()> { + fn layout_item( + &mut self, + engine: &mut Engine, + mut item: FlowItem, + ) -> SourceResult<()> { match item { FlowItem::Absolute(v, weak) => { if weak @@ -372,7 +386,7 @@ impl<'a> FlowLayouter<'a> { FlowItem::Frame { ref frame, movable, .. } => { let height = frame.height(); if !self.regions.size.y.fits(height) && !self.regions.in_last() { - self.finish_region(vt)?; + self.finish_region(engine)?; } self.regions.size.y -= height; @@ -380,12 +394,12 @@ impl<'a> FlowLayouter<'a> { let mut notes = Vec::new(); find_footnotes(&mut notes, frame); self.items.push(item); - if !self.handle_footnotes(vt, &mut notes, true, false)? { + if !self.handle_footnotes(engine, &mut notes, true, false)? { let item = self.items.pop(); - self.finish_region(vt)?; + self.finish_region(engine)?; self.items.extend(item); self.regions.size.y -= height; - self.handle_footnotes(vt, &mut notes, true, true)?; + self.handle_footnotes(engine, &mut notes, true, true)?; } return Ok(()); } @@ -429,7 +443,7 @@ impl<'a> FlowLayouter<'a> { if self.root { let mut notes = vec![]; find_footnotes(&mut notes, frame); - self.try_handle_footnotes(vt, notes)?; + self.try_handle_footnotes(engine, notes)?; } } FlowItem::Footnote(_) => {} @@ -440,7 +454,7 @@ impl<'a> FlowLayouter<'a> { } /// Finish the frame for one region. - fn finish_region(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn finish_region(&mut self, engine: &mut Engine) -> SourceResult<()> { // Trim weak spacing. while self .items @@ -567,23 +581,23 @@ impl<'a> FlowLayouter<'a> { // Try to place floats. for item in std::mem::take(&mut self.pending_floats) { - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } Ok(()) } /// Finish layouting and return the resulting fragment. - fn finish(mut self, vt: &mut Vt) -> SourceResult<Fragment> { + fn finish(mut self, engine: &mut Engine) -> SourceResult<Fragment> { if self.expand.y { while !self.regions.backlog.is_empty() { - self.finish_region(vt)?; + self.finish_region(engine)?; } } - self.finish_region(vt)?; + self.finish_region(engine)?; while !self.items.is_empty() { - self.finish_region(vt)?; + self.finish_region(engine)?; } Ok(Fragment::frames(self.finished)) @@ -593,12 +607,12 @@ impl<'a> FlowLayouter<'a> { impl FlowLayouter<'_> { fn try_handle_footnotes( &mut self, - vt: &mut Vt, + engine: &mut Engine, mut notes: Vec<FootnoteElem>, ) -> SourceResult<()> { - if self.root && !self.handle_footnotes(vt, &mut notes, false, false)? { - self.finish_region(vt)?; - self.handle_footnotes(vt, &mut notes, false, true)?; + if self.root && !self.handle_footnotes(engine, &mut notes, false, false)? { + self.finish_region(engine)?; + self.handle_footnotes(engine, &mut notes, false, true)?; } Ok(()) } @@ -607,7 +621,7 @@ impl FlowLayouter<'_> { #[tracing::instrument(skip_all)] fn handle_footnotes( &mut self, - vt: &mut Vt, + engine: &mut Engine, notes: &mut Vec<FootnoteElem>, movable: bool, force: bool, @@ -624,14 +638,14 @@ impl FlowLayouter<'_> { } if !self.has_footnotes { - self.layout_footnote_separator(vt)?; + self.layout_footnote_separator(engine)?; } self.regions.size.y -= self.footnote_config.gap; - let checkpoint = vt.locator.clone(); + let checkpoint = engine.locator.clone(); let frames = FootnoteEntry::new(notes[k].clone()) .pack() - .layout(vt, self.styles, self.regions.with_root(false))? + .layout(engine, self.styles, self.regions.with_root(false))? .into_frames(); // If the entries didn't fit, abort (to keep footnote and entry @@ -649,8 +663,8 @@ impl FlowLayouter<'_> { self.regions.size.y -= item.height(); } - // Undo Vt modifications. - *vt.locator = checkpoint; + // Undo locator modifications. + *engine.locator = checkpoint; return Ok(false); } @@ -659,8 +673,8 @@ impl FlowLayouter<'_> { for (i, frame) in frames.into_iter().enumerate() { find_footnotes(notes, &frame); if i > 0 { - self.finish_region(vt)?; - self.layout_footnote_separator(vt)?; + self.finish_region(engine)?; + self.layout_footnote_separator(engine)?; self.regions.size.y -= self.footnote_config.gap; } self.regions.size.y -= frame.height(); @@ -682,12 +696,12 @@ impl FlowLayouter<'_> { /// Layout and save the footnote separator, typically a line. #[tracing::instrument(skip_all)] - fn layout_footnote_separator(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn layout_footnote_separator(&mut self, engine: &mut Engine) -> SourceResult<()> { let expand = Axes::new(self.regions.expand.x, false); let pod = Regions::one(self.regions.base(), expand); let separator = &self.footnote_config.separator; - let mut frame = separator.layout(vt, self.styles, pod)?.into_frame(); + let mut frame = separator.layout(engine, self.styles, pod)?.into_frame(); frame.size_mut().y += self.footnote_config.clearance; frame.translate(Point::with_y(self.footnote_config.clearance)); diff --git a/crates/typst/src/layout/grid.rs b/crates/typst/src/layout/grid.rs index cc7d1d25..606aa4a7 100644 --- a/crates/typst/src/layout/grid.rs +++ b/crates/typst/src/layout/grid.rs @@ -3,12 +3,13 @@ use std::num::NonZeroUsize; use smallvec::{smallvec, SmallVec}; use crate::diag::{bail, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Array, Content, NativeElement, Resolve, StyleChain, Value, }; use crate::layout::{ Abs, Axes, Dir, Fr, Fragment, Frame, Layout, Length, Point, Regions, Rel, Size, - Sizing, Vt, + Sizing, }; use crate::syntax::Span; use crate::text::TextElem; @@ -128,7 +129,7 @@ impl Layout for GridElem { #[tracing::instrument(name = "GridElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -148,7 +149,7 @@ impl Layout for GridElem { ); // Measure the columns and layout the grid row-by-row. - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } @@ -311,24 +312,24 @@ impl<'a> GridLayouter<'a> { } /// Determines the columns sizes and then layouts the grid row-by-row. - pub fn layout(mut self, vt: &mut Vt) -> SourceResult<GridLayout> { - self.measure_columns(vt)?; + pub fn layout(mut self, engine: &mut Engine) -> SourceResult<GridLayout> { + self.measure_columns(engine)?; for y in 0..self.rows.len() { // Skip to next region if current one is full, but only for content // rows, not for gutter rows. if self.regions.is_full() && (!self.has_gutter || y % 2 == 0) { - self.finish_region(vt)?; + self.finish_region(engine)?; } match self.rows[y] { - Sizing::Auto => self.layout_auto_row(vt, y)?, - Sizing::Rel(v) => self.layout_relative_row(vt, v, y)?, + Sizing::Auto => self.layout_auto_row(engine, y)?, + Sizing::Rel(v) => self.layout_relative_row(engine, v, y)?, Sizing::Fr(v) => self.lrows.push(Row::Fr(v, y)), } } - self.finish_region(vt)?; + self.finish_region(engine)?; Ok(GridLayout { fragment: Fragment::frames(self.finished), @@ -339,7 +340,7 @@ impl<'a> GridLayouter<'a> { /// Determine all column sizes. #[tracing::instrument(name = "GridLayouter::measure_columns", skip_all)] - fn measure_columns(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn measure_columns(&mut self, engine: &mut Engine) -> SourceResult<()> { // Sum of sizes of resolved relative tracks. let mut rel = Abs::zero(); @@ -365,7 +366,7 @@ impl<'a> GridLayouter<'a> { let available = self.regions.size.x - rel; if available >= Abs::zero() { // Determine size of auto columns. - let (auto, count) = self.measure_auto_columns(vt, available)?; + let (auto, count) = self.measure_auto_columns(engine, available)?; // If there is remaining space, distribute it to fractional columns, // otherwise shrink auto columns. @@ -386,7 +387,7 @@ impl<'a> GridLayouter<'a> { /// Measure the size that is available to auto columns. fn measure_auto_columns( &mut self, - vt: &mut Vt, + engine: &mut Engine, available: Abs, ) -> SourceResult<(Abs, usize)> { let mut auto = Abs::zero(); @@ -413,7 +414,7 @@ impl<'a> GridLayouter<'a> { let size = Size::new(available, height); let pod = Regions::one(size, Axes::splat(false)); - let frame = cell.measure(vt, self.styles, pod)?.into_frame(); + let frame = cell.measure(engine, self.styles, pod)?.into_frame(); resolved.set_max(frame.width()); } } @@ -474,14 +475,14 @@ impl<'a> GridLayouter<'a> { /// Layout a row with automatic height. Such a row may break across multiple /// regions. - fn layout_auto_row(&mut self, vt: &mut Vt, y: usize) -> SourceResult<()> { + fn layout_auto_row(&mut self, engine: &mut Engine, y: usize) -> SourceResult<()> { // Determine the size for each region of the row. If the first region // ends up empty for some column, skip the region and remeasure. - let mut resolved = match self.measure_auto_row(vt, y, true)? { + let mut resolved = match self.measure_auto_row(engine, y, true)? { Some(resolved) => resolved, None => { - self.finish_region(vt)?; - self.measure_auto_row(vt, y, false)?.unwrap() + self.finish_region(engine)?; + self.measure_auto_row(engine, y, false)?.unwrap() } }; @@ -492,7 +493,7 @@ impl<'a> GridLayouter<'a> { // Layout into a single region. if let &[first] = resolved.as_slice() { - let frame = self.layout_single_row(vt, first, y)?; + let frame = self.layout_single_row(engine, first, y)?; self.push_row(frame, y); return Ok(()); } @@ -510,12 +511,12 @@ impl<'a> GridLayouter<'a> { } // Layout into multiple regions. - let fragment = self.layout_multi_row(vt, &resolved, y)?; + let fragment = self.layout_multi_row(engine, &resolved, y)?; let len = fragment.len(); for (i, frame) in fragment.into_iter().enumerate() { self.push_row(frame, y); if i + 1 < len { - self.finish_region(vt)?; + self.finish_region(engine)?; } } @@ -526,7 +527,7 @@ impl<'a> GridLayouter<'a> { /// if `can_skip` is false. fn measure_auto_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, y: usize, can_skip: bool, ) -> SourceResult<Option<Vec<Abs>>> { @@ -537,7 +538,7 @@ impl<'a> GridLayouter<'a> { let mut pod = self.regions; pod.size.x = rcol; - let frames = cell.measure(vt, self.styles, pod)?.into_frames(); + let frames = cell.measure(engine, self.styles, pod)?.into_frames(); // Skip the first region if one cell in it is empty. Then, // remeasure. @@ -568,17 +569,17 @@ impl<'a> GridLayouter<'a> { /// multiple regions, but it may force a region break. fn layout_relative_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, v: Rel<Length>, y: usize, ) -> SourceResult<()> { let resolved = v.resolve(self.styles).relative_to(self.regions.base().y); - let frame = self.layout_single_row(vt, resolved, y)?; + let frame = self.layout_single_row(engine, resolved, y)?; // Skip to fitting region. let height = frame.height(); while !self.regions.size.y.fits(height) && !self.regions.in_last() { - self.finish_region(vt)?; + self.finish_region(engine)?; // Don't skip multiple regions for gutter and don't push a row. if self.has_gutter && y % 2 == 1 { @@ -594,7 +595,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row with fixed height and return its frame. fn layout_single_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, height: Abs, y: usize, ) -> SourceResult<Frame> { @@ -612,7 +613,7 @@ impl<'a> GridLayouter<'a> { if self.rows[y] == Sizing::Auto { pod.full = self.regions.full; } - let frame = cell.layout(vt, self.styles, pod)?.into_frame(); + let frame = cell.layout(engine, self.styles, pod)?.into_frame(); output.push_frame(pos, frame); } @@ -625,7 +626,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row spanning multiple regions. fn layout_multi_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, heights: &[Abs], y: usize, ) -> SourceResult<Fragment> { @@ -648,7 +649,7 @@ impl<'a> GridLayouter<'a> { pod.size.x = rcol; // Push the layouted frames into the individual output frames. - let fragment = cell.layout(vt, self.styles, pod)?; + let fragment = cell.layout(engine, self.styles, pod)?; for (output, frame) in outputs.iter_mut().zip(fragment) { output.push_frame(pos, frame); } @@ -667,7 +668,7 @@ impl<'a> GridLayouter<'a> { } /// Finish rows for one region. - fn finish_region(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn finish_region(&mut self, engine: &mut Engine) -> SourceResult<()> { // Determine the height of existing rows in the region. let mut used = Abs::zero(); let mut fr = Fr::zero(); @@ -697,7 +698,7 @@ impl<'a> GridLayouter<'a> { Row::Fr(v, y) => { let remaining = self.regions.full - used; let height = v.share(fr, remaining); - (self.layout_single_row(vt, height, y)?, y) + (self.layout_single_row(engine, height, y)?, y) } }; diff --git a/crates/typst/src/layout/hide.rs b/crates/typst/src/layout/hide.rs index b72f2ad2..50ce8467 100644 --- a/crates/typst/src/layout/hide.rs +++ b/crates/typst/src/layout/hide.rs @@ -1,9 +1,9 @@ use smallvec::smallvec; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; use crate::introspection::{Meta, MetaElem}; -use crate::layout::Vt; /// Hides content without affecting layout. /// @@ -26,7 +26,7 @@ pub struct HideElem { impl Show for HideElem { #[tracing::instrument(name = "HideElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(MetaElem::set_data(smallvec![Meta::Hide]))) } } diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index 44b2e113..ba88f74e 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -11,12 +11,13 @@ use self::shaping::{ END_PUNCT_PAT, }; use crate::diag::{bail, SourceResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{Content, Resolve, Smart, StyleChain}; use crate::introspection::{Introspector, Locator, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BoxElem, Dir, Em, FixedAlign, Fr, Fragment, Frame, HElem, - Layout, Point, Regions, Size, Sizing, Spacing, Vt, + Layout, Point, Regions, Size, Sizing, Spacing, }; use crate::math::EquationElem; use crate::model::{Linebreaks, ParElem}; @@ -30,7 +31,7 @@ use crate::World; /// Layout's content inline. pub(crate) fn layout_inline( children: &[Prehashed<Content>], - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, consecutive: bool, region: Size, @@ -42,6 +43,7 @@ pub(crate) fn layout_inline( children: &[Prehashed<Content>], world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, @@ -50,7 +52,13 @@ pub(crate) fn layout_inline( expand: bool, ) -> SourceResult<Fragment> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; // Collect all text into one string for BiDi analysis. let (text, segments, spans) = collect(children, &styles, consecutive)?; @@ -58,28 +66,29 @@ pub(crate) fn layout_inline( // Perform BiDi analysis and then prepare paragraph layout by building a // representation on which we can do line breaking without layouting // each and every line from scratch. - let p = prepare(&mut vt, children, &text, segments, spans, styles, region)?; + let p = prepare(&mut engine, children, &text, segments, spans, styles, region)?; // Break the paragraph into lines. - let lines = linebreak(&vt, &p, region.x - p.hang); + let lines = linebreak(&engine, &p, region.x - p.hang); // Stack the lines into one frame per region. - finalize(&mut vt, &p, &lines, region, expand) + finalize(&mut engine, &p, &lines, region, expand) } let fragment = cached( children, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, consecutive, region, expand, )?; - vt.locator.visit_frames(&fragment); + engine.locator.visit_frames(&fragment); Ok(fragment) } @@ -520,7 +529,7 @@ fn collect<'a>( /// Prepare paragraph layout by shaping the whole paragraph and layouting all /// contained inline-level content. fn prepare<'a>( - vt: &mut Vt, + engine: &mut Engine, children: &'a [Prehashed<Content>], text: &'a str, segments: Vec<(Segment<'a>, StyleChain<'a>)>, @@ -546,7 +555,7 @@ fn prepare<'a>( let end = cursor + segment.len(); match segment { Segment::Text(_) => { - shape_range(&mut items, vt, &bidi, cursor..end, &spans, styles); + shape_range(&mut items, engine, &bidi, cursor..end, &spans, styles); } Segment::Spacing(spacing) => match spacing { Spacing::Rel(v) => { @@ -559,7 +568,7 @@ fn prepare<'a>( }, Segment::Equation(equation) => { let pod = Regions::one(region, Axes::splat(false)); - let mut frame = equation.layout(vt, styles, pod)?.into_frame(); + let mut frame = equation.layout(engine, styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } @@ -568,7 +577,7 @@ fn prepare<'a>( items.push(Item::Fractional(v, Some((elem, styles)))); } else { let pod = Regions::one(region, Axes::splat(false)); - let mut frame = elem.layout(vt, styles, pod)?.into_frame(); + let mut frame = elem.layout(engine, styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } @@ -655,7 +664,7 @@ fn add_cjk_latin_spacing(items: &mut [Item]) { /// items for them. fn shape_range<'a>( items: &mut Vec<Item<'a>>, - vt: &Vt, + engine: &Engine, bidi: &BidiInfo<'a>, range: Range, spans: &SpanMapper, @@ -666,8 +675,16 @@ fn shape_range<'a>( let region = TextElem::region_in(styles); let mut process = |range: Range, level: BidiLevel| { let dir = if level.is_ltr() { Dir::LTR } else { Dir::RTL }; - let shaped = - shape(vt, range.start, &bidi.text[range], spans, styles, dir, lang, region); + let shaped = shape( + engine, + range.start, + &bidi.text[range], + spans, + styles, + dir, + lang, + region, + ); items.push(Item::Text(shaped)); }; @@ -732,7 +749,7 @@ fn shared_get<T: PartialEq>( } /// Find suitable linebreaks. -fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak<'a>(engine: &Engine, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { let linebreaks = p.linebreaks.unwrap_or_else(|| { if p.justify { Linebreaks::Optimized @@ -742,22 +759,26 @@ fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { }); match linebreaks { - Linebreaks::Simple => linebreak_simple(vt, p, width), - Linebreaks::Optimized => linebreak_optimized(vt, p, width), + Linebreaks::Simple => linebreak_simple(engine, p, width), + Linebreaks::Optimized => linebreak_optimized(engine, p, width), } } /// Perform line breaking in simple first-fit style. This means that we build /// lines greedily, always taking the longest possible line. This may lead to /// very unbalanced line, but is fast and simple. -fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak_simple<'a>( + engine: &Engine, + p: &'a Preparation<'a>, + width: Abs, +) -> Vec<Line<'a>> { let mut lines = Vec::with_capacity(16); let mut start = 0; let mut last = None; breakpoints(p, |end, breakpoint| { // Compute the line and its size. - let mut attempt = line(vt, p, start..end, breakpoint); + let mut attempt = line(engine, p, start..end, breakpoint); // If the line doesn't fit anymore, we push the last fitting attempt // into the stack and rebuild the line from the attempt's end. The @@ -766,7 +787,7 @@ fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line if let Some((last_attempt, last_end)) = last.take() { lines.push(last_attempt); start = last_end; - attempt = line(vt, p, start..end, breakpoint); + attempt = line(engine, p, start..end, breakpoint); } } @@ -806,7 +827,11 @@ fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line /// computed and stored in dynamic programming table) is minimal. The final /// result is simply the layout determined for the last breakpoint at the end of /// text. -fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak_optimized<'a>( + engine: &Engine, + p: &'a Preparation<'a>, + width: Abs, +) -> Vec<Line<'a>> { /// The cost of a line or paragraph layout. type Cost = f64; @@ -829,7 +854,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L let mut table = vec![Entry { pred: 0, total: 0.0, - line: line(vt, p, 0..0, Breakpoint::Mandatory), + line: line(engine, p, 0..0, Breakpoint::Mandatory), }]; let em = p.size; @@ -844,7 +869,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L // Layout the line. let start = pred.line.end; - let attempt = line(vt, p, start..end, breakpoint); + let attempt = line(engine, p, start..end, breakpoint); // Determine how much the line's spaces would need to be stretched // to make it the desired width. @@ -953,7 +978,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L /// Create a line which spans the given range. fn line<'a>( - vt: &Vt, + engine: &Engine, p: &'a Preparation, mut range: Range, breakpoint: Breakpoint, @@ -1016,9 +1041,9 @@ fn line<'a>( // are no other items in the line. if hyphen || start + shaped.text.len() > range.end || maybe_adjust_last_glyph { if hyphen || start < range.end || before.is_empty() { - let mut reshaped = shaped.reshape(vt, &p.spans, start..range.end); + let mut reshaped = shaped.reshape(engine, &p.spans, start..range.end); if hyphen || shy { - reshaped.push_hyphen(vt, p.fallback); + reshaped.push_hyphen(engine, p.fallback); } if let Some(last_glyph) = reshaped.glyphs.last() { @@ -1069,7 +1094,7 @@ fn line<'a>( if range.start + shaped.text.len() > end || maybe_adjust_first_glyph { // If the range is empty, we don't want to push an empty text item. if range.start < end { - let reshaped = shaped.reshape(vt, &p.spans, range.start..end); + let reshaped = shaped.reshape(engine, &p.spans, range.start..end); width += reshaped.width; first = Some(Item::Text(reshaped)); } @@ -1129,7 +1154,7 @@ fn line<'a>( /// Combine layouted lines into one frame per region. fn finalize( - vt: &mut Vt, + engine: &mut Engine, p: &Preparation, lines: &[Line], region: Size, @@ -1150,7 +1175,7 @@ fn finalize( // Stack the lines into one frame per region. let mut frames: Vec<Frame> = lines .iter() - .map(|line| commit(vt, p, line, width, region.y)) + .map(|line| commit(engine, p, line, width, region.y)) .collect::<SourceResult<_>>()?; // Prevent orphans. @@ -1181,7 +1206,7 @@ fn merge(first: &mut Frame, second: Frame, leading: Abs) { /// Commit to a line and build its frame. fn commit( - vt: &mut Vt, + engine: &mut Engine, p: &Preparation, line: &Line, width: Abs, @@ -1276,7 +1301,7 @@ fn commit( if let Some((elem, styles)) = elem { let region = Size::new(amount, full); let pod = Regions::one(region, Axes::new(true, false)); - let mut frame = elem.layout(vt, *styles, pod)?.into_frame(); + let mut frame = elem.layout(engine, *styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(*styles))); push(&mut offset, frame); } else { @@ -1284,7 +1309,8 @@ fn commit( } } Item::Text(shaped) => { - let frame = shaped.build(vt, justification_ratio, extra_justification); + let frame = + shaped.build(engine, justification_ratio, extra_justification); push(&mut offset, frame); } Item::Frame(frame) | Item::Meta(frame) => { diff --git a/crates/typst/src/layout/inline/shaping.rs b/crates/typst/src/layout/inline/shaping.rs index 69e70967..08a617dc 100644 --- a/crates/typst/src/layout/inline/shaping.rs +++ b/crates/typst/src/layout/inline/shaping.rs @@ -9,8 +9,9 @@ use rustybuzz::{Tag, UnicodeBuffer}; use unicode_script::{Script, UnicodeScript}; use super::SpanMapper; +use crate::engine::Engine; use crate::foundations::StyleChain; -use crate::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size, Vt}; +use crate::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size}; use crate::syntax::Span; use crate::text::{ decorate, families, features, variant, Font, FontVariant, Glyph, Lang, Region, @@ -213,11 +214,11 @@ impl<'a> ShapedText<'a> { /// [justifiable glyph](ShapedGlyph::is_justifiable) will get. pub fn build( &self, - vt: &Vt, + engine: &Engine, justification_ratio: f64, extra_justification: Abs, ) -> Frame { - let (top, bottom) = self.measure(vt); + let (top, bottom) = self.measure(engine); let size = Size::new(self.width, top + bottom); let mut offset = Abs::zero(); @@ -307,7 +308,7 @@ impl<'a> ShapedText<'a> { } /// Measure the top and bottom extent of this text. - fn measure(&self, vt: &Vt) -> (Abs, Abs) { + fn measure(&self, engine: &Engine) -> (Abs, Abs) { let mut top = Abs::zero(); let mut bottom = Abs::zero(); @@ -323,7 +324,7 @@ impl<'a> ShapedText<'a> { if self.glyphs.is_empty() { // When there are no glyphs, we just use the vertical metrics of the // first available font. - let world = vt.world; + let world = engine.world; for family in families(self.styles) { if let Some(font) = world .book() @@ -387,7 +388,7 @@ impl<'a> ShapedText<'a> { /// The text `range` is relative to the whole paragraph. pub fn reshape( &'a self, - vt: &Vt, + engine: &Engine, spans: &SpanMapper, text_range: Range<usize>, ) -> ShapedText<'a> { @@ -409,7 +410,7 @@ impl<'a> ShapedText<'a> { } } else { shape( - vt, + engine, text_range.start, text, spans, @@ -422,8 +423,8 @@ impl<'a> ShapedText<'a> { } /// Push a hyphen to end of the text. - pub fn push_hyphen(&mut self, vt: &Vt, fallback: bool) { - let world = vt.world; + pub fn push_hyphen(&mut self, engine: &Engine, fallback: bool) { + let world = engine.world; let book = world.book(); let fallback_func = if fallback { Some(|| book.select_fallback(None, self.variant, "-")) @@ -553,7 +554,7 @@ impl Debug for ShapedText<'_> { /// Holds shaping results and metadata common to all shaped segments. struct ShapingContext<'a, 'v> { - vt: &'a Vt<'v>, + engine: &'a Engine<'v>, spans: &'a SpanMapper, glyphs: Vec<ShapedGlyph>, used: Vec<Font>, @@ -568,7 +569,7 @@ struct ShapingContext<'a, 'v> { /// Shape text into [`ShapedText`]. #[allow(clippy::too_many_arguments)] pub(super) fn shape<'a>( - vt: &Vt, + engine: &Engine, base: usize, text: &'a str, spans: &SpanMapper, @@ -579,7 +580,7 @@ pub(super) fn shape<'a>( ) -> ShapedText<'a> { let size = TextElem::size_in(styles); let mut ctx = ShapingContext { - vt, + engine, spans, size, glyphs: vec![], @@ -630,7 +631,7 @@ fn shape_segment<'a>( } // Find the next available family. - let world = ctx.vt.world; + let world = ctx.engine.world; let book = world.book(); let mut selection = families.find_map(|family| { book.select(family, ctx.variant) diff --git a/crates/typst/src/layout/layout.rs b/crates/typst/src/layout/layout.rs index e2c0fa2b..45b7c54a 100644 --- a/crates/typst/src/layout/layout.rs +++ b/crates/typst/src/layout/layout.rs @@ -1,6 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{dict, elem, func, Content, Func, NativeElement, StyleChain}; -use crate::layout::{Fragment, Layout, Regions, Size, Vt}; +use crate::layout::{Fragment, Layout, Regions, Size}; /// Provides access to the current outer container's (or page's, if none) size /// (width and height). @@ -68,7 +69,7 @@ impl Layout for LayoutElem { #[tracing::instrument(name = "LayoutElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -77,8 +78,8 @@ impl Layout for LayoutElem { let Size { x, y } = regions.base(); let result = self .func() - .call_vt(vt, [dict! { "width" => x, "height" => y }])? + .call(engine, [dict! { "width" => x, "height" => y }])? .display(); - result.layout(vt, styles, regions) + result.layout(engine, styles, regions) } } diff --git a/crates/typst/src/layout/measure.rs b/crates/typst/src/layout/measure.rs index 2b82c58b..1aff7ad4 100644 --- a/crates/typst/src/layout/measure.rs +++ b/crates/typst/src/layout/measure.rs @@ -1,5 +1,5 @@ use crate::diag::SourceResult; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{dict, func, Content, Dict, StyleChain, Styles}; use crate::layout::{Abs, Axes, Layout, Regions, Size}; @@ -41,8 +41,8 @@ use crate::layout::{Abs, Axes, Layout, Regions, Size}; /// `height`, both of type [`length`]($length). #[func] pub fn measure( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The content whose size to measure. content: Content, /// The styles with which to layout the content. @@ -50,7 +50,7 @@ pub fn measure( ) -> SourceResult<Dict> { let pod = Regions::one(Axes::splat(Abs::inf()), Axes::splat(false)); let styles = StyleChain::new(&styles); - let frame = content.measure(&mut vm.vt, styles, pod)?.into_frame(); + let frame = content.measure(engine, styles, pod)?.into_frame(); let Size { x, y } = frame.size(); Ok(dict! { "width" => x, "height" => y }) } diff --git a/crates/typst/src/layout/mod.rs b/crates/typst/src/layout/mod.rs index f291cfe9..1e1bcf9b 100644 --- a/crates/typst/src/layout/mod.rs +++ b/crates/typst/src/layout/mod.rs @@ -34,7 +34,6 @@ mod size; mod spacing; mod stack; mod transform; -mod vt; pub use self::abs::*; pub use self::align::*; @@ -67,13 +66,13 @@ pub use self::size::*; pub use self::spacing::*; pub use self::stack::*; pub use self::transform::*; -pub use self::vt::*; pub(crate) use self::inline::*; use comemo::{Tracked, TrackedMut}; -use crate::diag::SourceResult; +use crate::diag::{bail, error, SourceResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{category, Category, Content, Scope, StyleChain}; use crate::introspection::{Introspector, Locator}; @@ -122,7 +121,11 @@ pub fn define(global: &mut Scope) { /// Root-level layout. pub trait LayoutRoot { /// Layout into one frame per page. - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document>; + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document>; } /// Layout into regions. @@ -130,7 +133,7 @@ pub trait Layout { /// Layout into one frame per region. fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment>; @@ -142,50 +145,64 @@ pub trait Layout { #[tracing::instrument(name = "Layout::measure", skip_all)] fn measure( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { - let mut locator = Locator::chained(vt.locator.track()); - let mut vt = Vt { - world: vt.world, - introspector: vt.introspector, + let mut locator = Locator::chained(engine.locator.track()); + let mut engine = Engine { + world: engine.world, + route: engine.route.clone(), + introspector: engine.introspector, locator: &mut locator, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), + tracer: TrackedMut::reborrow_mut(&mut engine.tracer), }; - self.layout(&mut vt, styles, regions) + self.layout(&mut engine, styles, regions) } } impl LayoutRoot for Content { #[tracing::instrument(name = "Content::layout_root", skip_all)] - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document> { #[comemo::memoize] fn cached( content: &Content, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, ) -> SourceResult<Document> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let scratch = Scratch::default(); - let (realized, styles) = realize_root(&mut vt, &scratch, content, styles)?; + let (realized, styles) = + realize_root(&mut engine, &scratch, content, styles)?; realized .with::<dyn LayoutRoot>() .unwrap() - .layout_root(&mut vt, styles) + .layout_root(&mut engine, styles) } tracing::info!("Starting layout"); cached( self, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, ) } @@ -195,7 +212,7 @@ impl Layout for Content { #[tracing::instrument(name = "Content::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -205,34 +222,49 @@ impl Layout for Content { content: &Content, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; + + if engine.route.exceeding() { + bail!(error!(content.span(), "maximum layout depth exceeded") + .with_hint("try to reduce the amount of nesting in your layout")); + } + let scratch = Scratch::default(); - let (realized, styles) = realize_block(&mut vt, &scratch, content, styles)?; + let (realized, styles) = + realize_block(&mut engine, &scratch, content, styles)?; realized .with::<dyn Layout>() .unwrap() - .layout(&mut vt, styles, regions) + .layout(&mut engine, styles, regions) } tracing::info!("Layouting `Content`"); let fragment = cached( self, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, regions, )?; - vt.locator.visit_frames(&fragment); + engine.locator.visit_frames(&fragment); Ok(fragment) } } diff --git a/crates/typst/src/layout/pad.rs b/crates/typst/src/layout/pad.rs index f5762409..35dfd0b4 100644 --- a/crates/typst/src/layout/pad.rs +++ b/crates/typst/src/layout/pad.rs @@ -1,8 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Resolve, StyleChain}; -use crate::layout::{ - Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size, Vt, -}; +use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size}; /// Adds spacing around content. /// @@ -63,7 +62,7 @@ impl Layout for PadElem { #[tracing::instrument(name = "PadElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -78,7 +77,7 @@ impl Layout for PadElem { let mut backlog = vec![]; let padding = sides.resolve(styles); let pod = regions.map(&mut backlog, |size| shrink(size, padding)); - let mut fragment = self.body().layout(vt, styles, pod)?; + let mut fragment = self.body().layout(engine, styles, pod)?; for frame in &mut fragment { // Apply the padding inversely such that the grown size padded diff --git a/crates/typst/src/layout/page.rs b/crates/typst/src/layout/page.rs index 411f9769..96e6d96a 100644 --- a/crates/typst/src/layout/page.rs +++ b/crates/typst/src/layout/page.rs @@ -4,6 +4,7 @@ use std::ptr; use std::str::FromStr; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Resolve, Smart, StyleChain, Value, @@ -11,7 +12,7 @@ use crate::foundations::{ use crate::introspection::{Counter, CounterKey, ManualPageCounter, Meta}; use crate::layout::{ Abs, Align, AlignElem, Axes, ColumnsElem, Dir, Fragment, Frame, HAlign, Layout, - Length, Point, Ratio, Regions, Rel, Sides, Size, VAlign, Vt, + Length, Point, Ratio, Regions, Rel, Sides, Size, VAlign, }; use crate::model::Numbering; @@ -342,7 +343,7 @@ impl PageElem { #[tracing::instrument(skip_all)] pub fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, page_counter: &mut ManualPageCounter, extend_to: Option<Parity>, @@ -393,7 +394,7 @@ impl PageElem { regions.root = true; // Layout the child. - let mut frames = child.layout(vt, styles, regions)?.into_frames(); + let mut frames = child.layout(engine, styles, regions)?.into_frames(); // Align the child to the pagebreak's parity. // Check for page count after adding the pending frames @@ -496,7 +497,7 @@ impl PageElem { let sub = content .clone() .styled(AlignElem::set_alignment(align)) - .layout(vt, styles, pod)? + .layout(engine, styles, pod)? .into_frame(); if ptr::eq(marginal, &header) || ptr::eq(marginal, &background) { @@ -510,7 +511,7 @@ impl PageElem { frame.fill(fill.clone()); } - page_counter.visit(vt, frame)?; + page_counter.visit(engine, frame)?; // Add a PDF page label if there is a numbering. if let Some(num) = numbering { @@ -675,10 +676,14 @@ pub enum Marginal { impl Marginal { /// Resolve the marginal based on the page number. - pub fn resolve(&self, vt: &mut Vt, page: usize) -> SourceResult<Cow<'_, Content>> { + pub fn resolve( + &self, + engine: &mut Engine, + page: usize, + ) -> SourceResult<Cow<'_, Content>> { Ok(match self { Self::Content(content) => Cow::Borrowed(content), - Self::Func(func) => Cow::Owned(func.call_vt(vt, [page])?.display()), + Self::Func(func) => Cow::Owned(func.call(engine, [page])?.display()), }) } } diff --git a/crates/typst/src/layout/place.rs b/crates/typst/src/layout/place.rs index 537b47ed..3c0012aa 100644 --- a/crates/typst/src/layout/place.rs +++ b/crates/typst/src/layout/place.rs @@ -1,10 +1,9 @@ use crate::diag::{bail, At, Hint, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Behave, Behaviour, Content, NativeElement, Smart, StyleChain, }; -use crate::layout::{ - Align, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlign, Vt, -}; +use crate::layout::{Align, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlign}; /// Places content at an absolute position. /// @@ -91,7 +90,7 @@ impl Layout for PlaceElem { #[tracing::instrument(name = "PlaceElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -118,7 +117,7 @@ impl Layout for PlaceElem { .aligned(alignment.unwrap_or_else(|| Align::CENTER)); let pod = Regions::one(base, Axes::splat(false)); - let frame = child.layout(vt, styles, pod)?.into_frame(); + let frame = child.layout(engine, styles, pod)?.into_frame(); Ok(Fragment::frame(frame)) } } diff --git a/crates/typst/src/layout/repeat.rs b/crates/typst/src/layout/repeat.rs index 29e34e18..c733ea7d 100644 --- a/crates/typst/src/layout/repeat.rs +++ b/crates/typst/src/layout/repeat.rs @@ -1,7 +1,8 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, StyleChain}; use crate::layout::{ - Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size, Vt, + Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size, }; use crate::util::Numeric; @@ -37,12 +38,12 @@ impl Layout for RepeatElem { #[tracing::instrument(name = "RepeatElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.size, Axes::new(false, false)); - let piece = self.body().layout(vt, styles, pod)?.into_frame(); + let piece = self.body().layout(engine, styles, pod)?.into_frame(); let align = AlignElem::alignment_in(styles).resolve(styles); let fill = regions.size.x; diff --git a/crates/typst/src/layout/stack.rs b/crates/typst/src/layout/stack.rs index e4dd029a..fe36cc63 100644 --- a/crates/typst/src/layout/stack.rs +++ b/crates/typst/src/layout/stack.rs @@ -1,10 +1,11 @@ use std::fmt::{self, Debug, Formatter}; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{cast, elem, Content, Resolve, StyleChain}; use crate::layout::{ Abs, AlignElem, Axes, Axis, Dir, FixedAlign, Fr, Fragment, Frame, Layout, Point, - Regions, Size, Spacing, Vt, + Regions, Size, Spacing, }; use crate::util::{Get, Numeric}; @@ -54,7 +55,7 @@ impl Layout for StackElem { #[tracing::instrument(name = "StackElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -75,7 +76,7 @@ impl Layout for StackElem { layouter.layout_spacing(kind); } - layouter.layout_block(vt, block, styles)?; + layouter.layout_block(engine, block, styles)?; deferred = spacing; } } @@ -199,7 +200,7 @@ impl<'a> StackLayouter<'a> { #[tracing::instrument(name = "StackLayouter::layout_block", skip_all)] fn layout_block( &mut self, - vt: &mut Vt, + engine: &mut Engine, block: &Content, styles: StyleChain, ) -> SourceResult<()> { @@ -217,7 +218,7 @@ impl<'a> StackLayouter<'a> { } .resolve(styles); - let fragment = block.layout(vt, styles, self.regions)?; + let fragment = block.layout(engine, styles, self.regions)?; let len = fragment.len(); for (i, frame) in fragment.into_iter().enumerate() { // Grow our size, shrink the region and save the frame for later. diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs index 51cc5d54..bfc35825 100644 --- a/crates/typst/src/layout/transform.rs +++ b/crates/typst/src/layout/transform.rs @@ -1,8 +1,9 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Resolve, StyleChain}; use crate::layout::{ Abs, Align, Angle, Axes, FixedAlign, Fragment, HAlign, Layout, Length, Ratio, - Regions, Rel, VAlign, Vt, + Regions, Rel, VAlign, }; /// Moves content without affecting layout. @@ -40,12 +41,12 @@ impl Layout for MoveElem { #[tracing::instrument(name = "MoveElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let delta = Axes::new(self.dx(styles), self.dy(styles)).resolve(styles); let delta = delta.zip_map(regions.base(), Rel::relative_to); frame.translate(delta.to_point()); @@ -106,12 +107,12 @@ impl Layout for RotateElem { #[tracing::instrument(name = "RotateElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let Axes { x, y } = self .origin(styles) .resolve(styles) @@ -171,12 +172,12 @@ impl Layout for ScaleElem { #[tracing::instrument(name = "ScaleElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let Axes { x, y } = self .origin(styles) .resolve(styles) diff --git a/crates/typst/src/layout/vt.rs b/crates/typst/src/layout/vt.rs deleted file mode 100644 index 78b8c511..00000000 --- a/crates/typst/src/layout/vt.rs +++ /dev/null @@ -1,39 +0,0 @@ -use comemo::{Tracked, TrackedMut}; - -use crate::diag::SourceResult; -use crate::eval::Tracer; -use crate::introspection::{Introspector, Locator}; -use crate::World; - -/// A virtual typesetter. -/// -/// Holds the state needed during compilation. -pub struct Vt<'a> { - /// The compilation environment. - pub world: Tracked<'a, dyn World + 'a>, - /// Provides access to information about the document. - pub introspector: Tracked<'a, Introspector>, - /// Provides stable identities to elements. - pub locator: &'a mut Locator<'a>, - /// The tracer for inspection of the values an expression produces. - pub tracer: TrackedMut<'a, Tracer>, -} - -impl Vt<'_> { - /// Perform 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 - where - F: FnOnce(&mut Self) -> SourceResult<T>, - T: Default, - { - match f(self) { - Ok(value) => value, - Err(errors) => { - self.tracer.delay(errors); - T::default() - } - } - } -} diff --git a/crates/typst/src/lib.rs b/crates/typst/src/lib.rs index 8d0001c8..52634d45 100644 --- a/crates/typst/src/lib.rs +++ b/crates/typst/src/lib.rs @@ -40,6 +40,7 @@ extern crate self as typst; #[macro_use] pub mod util; pub mod diag; +pub mod engine; pub mod eval; pub mod foundations; pub mod introspection; @@ -62,12 +63,13 @@ use comemo::{Prehashed, Track, Tracked, Validate}; use ecow::{EcoString, EcoVec}; use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult}; -use crate::eval::{Route, Tracer}; +use crate::engine::{Engine, Route}; +use crate::eval::Tracer; use crate::foundations::{ Array, Bytes, Content, Datetime, Module, Scope, StyleChain, Styles, }; use crate::introspection::{Introspector, Locator}; -use crate::layout::{Align, Dir, LayoutRoot, Vt}; +use crate::layout::{Align, Dir, LayoutRoot}; use crate::model::Document; use crate::syntax::{FileId, PackageSpec, Source, Span}; use crate::text::{Font, FontBook}; @@ -122,15 +124,17 @@ fn typeset( let constraint = <Introspector as Validate>::Constraint::new(); let mut locator = Locator::new(); - let mut vt = Vt { + let mut engine = Engine { world, + route: Route::default(), tracer: tracer.track_mut(), locator: &mut locator, introspector: introspector.track_with(&constraint), }; // Layout! - document = content.layout_root(&mut vt, styles)?; + document = content.layout_root(&mut engine, styles)?; + introspector = Introspector::new(&document.pages); iter += 1; diff --git a/crates/typst/src/loading/cbor.rs b/crates/typst/src/loading/cbor.rs index a1189dbe..ddf559f3 100644 --- a/crates/typst/src/loading/cbor.rs +++ b/crates/typst/src/loading/cbor.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Bytes, Value}; use crate::syntax::Spanned; use crate::World; @@ -16,14 +16,14 @@ use crate::World; /// whether they are whole numbers. #[func(scope, title = "CBOR")] pub fn cbor( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a CBOR file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; cbor::decode(Spanned::new(data, span)) } diff --git a/crates/typst/src/loading/csv.rs b/crates/typst/src/loading/csv.rs index e195f190..0d009560 100644 --- a/crates/typst/src/loading/csv.rs +++ b/crates/typst/src/loading/csv.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{bail, At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{cast, func, scope, Array, IntoValue, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -26,8 +26,8 @@ use crate::World; /// ``` #[func(scope, title = "CSV")] pub fn csv( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a CSV file. path: Spanned<EcoString>, /// The delimiter that separates columns in the CSV file. @@ -37,8 +37,8 @@ pub fn csv( delimiter: Delimiter, ) -> SourceResult<Array> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; self::csv::decode(Spanned::new(Readable::Bytes(data), span), delimiter) } diff --git a/crates/typst/src/loading/json.rs b/crates/typst/src/loading/json.rs index cf209971..aae1f4ad 100644 --- a/crates/typst/src/loading/json.rs +++ b/crates/typst/src/loading/json.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -46,14 +46,14 @@ use crate::World; /// ``` #[func(scope, title = "JSON")] pub fn json( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a JSON file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; json::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/read.rs b/crates/typst/src/loading/read.rs index 49a86699..50772bee 100644 --- a/crates/typst/src/loading/read.rs +++ b/crates/typst/src/loading/read.rs @@ -1,7 +1,7 @@ use ecow::EcoString; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, Cast}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -24,8 +24,8 @@ use crate::World; /// ``` #[func] pub fn read( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a file. path: Spanned<EcoString>, /// The encoding to read the file with. @@ -36,8 +36,8 @@ pub fn read( encoding: Option<Encoding>, ) -> SourceResult<Readable> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; Ok(match encoding { None => Readable::Bytes(data), Some(Encoding::Utf8) => Readable::Str( diff --git a/crates/typst/src/loading/toml.rs b/crates/typst/src/loading/toml.rs index a4388f74..6884e6fe 100644 --- a/crates/typst/src/loading/toml.rs +++ b/crates/typst/src/loading/toml.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::{is_newline, Spanned}; @@ -29,14 +29,14 @@ use crate::World; /// ``` #[func(scope, title = "TOML")] pub fn toml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a TOML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; toml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/xml.rs b/crates/typst/src/loading/xml.rs index 73aeb32a..338b2f30 100644 --- a/crates/typst/src/loading/xml.rs +++ b/crates/typst/src/loading/xml.rs @@ -1,7 +1,7 @@ use ecow::EcoString; use crate::diag::{format_xml_like_error, At, FileError, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{dict, func, scope, Array, Dict, IntoValue, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -57,14 +57,14 @@ use crate::World; /// ``` #[func(scope, title = "XML")] pub fn xml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to an XML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; xml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/yaml.rs b/crates/typst/src/loading/yaml.rs index 03dd2a2c..501e3066 100644 --- a/crates/typst/src/loading/yaml.rs +++ b/crates/typst/src/loading/yaml.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -38,14 +38,14 @@ use crate::World; /// ``` #[func(scope, title = "YAML")] pub fn yaml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a YAML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; yaml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/math/cancel.rs b/crates/typst/src/math/cancel.rs index 7a72f44a..6d3026b8 100644 --- a/crates/typst/src/math/cancel.rs +++ b/crates/typst/src/math/cancel.rs @@ -191,7 +191,7 @@ fn draw_cancel_line( CancelAngle::Angle(v) => *v, // This specifies a function that takes the default angle as input. CancelAngle::Func(func) => { - func.call_vt(ctx.vt, [default])?.cast().at(span)? + func.call(ctx.engine, [default])?.cast().at(span)? } }, }; diff --git a/crates/typst/src/math/ctx.rs b/crates/typst/src/math/ctx.rs index 0f7ad933..9352f08b 100644 --- a/crates/typst/src/math/ctx.rs +++ b/crates/typst/src/math/ctx.rs @@ -9,8 +9,9 @@ use unicode_math_class::MathClass; use unicode_segmentation::UnicodeSegmentation; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{Content, NativeElement, Smart, StyleChain, Styles}; -use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size, Vt}; +use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathFragment, MathRow, MathSize, MathStyle, MathVariant, THICK, @@ -43,7 +44,7 @@ macro_rules! percent { /// The context for math layout. pub struct MathContext<'a, 'b, 'v> { - pub vt: &'v mut Vt<'b>, + pub engine: &'v mut Engine<'b>, pub regions: Regions<'static>, pub font: &'a Font, pub ttf: &'a ttf_parser::Face<'a>, @@ -62,7 +63,7 @@ pub struct MathContext<'a, 'b, 'v> { impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn new( - vt: &'v mut Vt<'b>, + engine: &'v mut Engine<'b>, styles: StyleChain<'a>, regions: Regions, font: &'a Font, @@ -103,7 +104,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { let variant = variant(styles); Self { - vt, + engine, regions: Regions::one(regions.base(), Axes::splat(false)), font, ttf: font.ttf(), @@ -167,13 +168,13 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn layout_box(&mut self, boxed: &BoxElem) -> SourceResult<Frame> { Ok(boxed - .layout(self.vt, self.outer.chain(&self.local), self.regions)? + .layout(self.engine, self.outer.chain(&self.local), self.regions)? .into_frame()) } pub fn layout_content(&mut self, content: &Content) -> SourceResult<Frame> { Ok(content - .layout(self.vt, self.outer.chain(&self.local), self.regions)? + .layout(self.engine, self.outer.chain(&self.local), self.regions)? .into_frame()) } @@ -270,7 +271,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { let frame = ParElem::new(vec![Prehashed::new(elem)]) .spanned(span) .layout( - self.vt, + self.engine, self.outer.chain(&self.local), false, Size::splat(Abs::inf()), @@ -288,7 +289,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { } pub fn realize(&mut self, content: &Content) -> SourceResult<Option<Content>> { - realize(self.vt, content, self.outer.chain(&self.local)) + realize(self.engine, content, self.outer.chain(&self.local)) } pub fn style(&mut self, style: MathStyle) { diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs index fb58a5b7..f5fa6061 100644 --- a/crates/typst/src/math/equation.rs +++ b/crates/typst/src/math/equation.rs @@ -1,6 +1,7 @@ use std::num::NonZeroUsize; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Content, Finalize, Guard, NativeElement, Resolve, Show, Smart, StyleChain, Synthesize, @@ -8,7 +9,7 @@ use crate::foundations::{ use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ Abs, Align, AlignElem, Axes, Dir, Em, FixedAlign, Fragment, Layout, Point, Regions, - Size, Vt, + Size, }; use crate::math::{LayoutMath, MathContext}; use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement}; @@ -88,12 +89,18 @@ pub struct EquationElem { } impl Synthesize for EquationElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { // Resolve the supplement. let supplement = match self.supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?, + Smart::Custom(Some(supplement)) => { + supplement.resolve(engine, [self.clone()])? + } }; self.push_block(self.block(styles)); @@ -106,7 +113,7 @@ impl Synthesize for EquationElem { impl Show for EquationElem { #[tracing::instrument(name = "EquationElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.clone().pack().guarded(Guard::Base(Self::elem())); if self.block(styles) { realized = AlignElem::new(realized).pack(); @@ -133,7 +140,7 @@ impl Layout for EquationElem { #[tracing::instrument(name = "EquationElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -143,7 +150,7 @@ impl Layout for EquationElem { // Find a math font. let variant = variant(styles); - let world = vt.world; + let world = engine.world; let Some(font) = families(styles).find_map(|family| { let id = world.book().select(family, variant)?; let font = world.font(id)?; @@ -153,7 +160,7 @@ impl Layout for EquationElem { bail!(self.span(), "current font does not support math"); }; - let mut ctx = MathContext::new(vt, styles, regions, &font, block); + let mut ctx = MathContext::new(engine, styles, regions, &font, block); let mut frame = ctx.layout_frame(self)?; if block { @@ -161,7 +168,7 @@ impl Layout for EquationElem { let pod = Regions::one(regions.base(), Axes::splat(false)); let counter = Counter::of(Self::elem()) .display(Some(numbering), false) - .layout(vt, styles, pod)? + .layout(engine, styles, pod)? .into_frame(); let full_counter_width = counter.width() + NUMBER_GUTTER.resolve(styles); @@ -274,7 +281,7 @@ impl Refable for EquationElem { } impl Outlinable for EquationElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.block(StyleChain::default()) { return Ok(None); } @@ -294,8 +301,8 @@ impl Outlinable for EquationElem { let numbers = self .counter() - .at(vt, self.location().unwrap())? - .display(vt, &numbering)?; + .at(engine, self.location().unwrap())? + .display(engine, &numbering)?; Ok(Some(supplement + numbers)) } diff --git a/crates/typst/src/model/bibliography.rs b/crates/typst/src/model/bibliography.rs index f6e189e1..626468dc 100644 --- a/crates/typst/src/model/bibliography.rs +++ b/crates/typst/src/model/bibliography.rs @@ -20,7 +20,8 @@ use smallvec::{smallvec, SmallVec}; use typed_arena::Arena; use crate::diag::{bail, error, At, FileError, SourceResult, StrResult}; -use crate::eval::{eval_string, EvalMode, Vm}; +use crate::engine::Engine; +use crate::eval::{eval_string, EvalMode}; use crate::foundations::{ cast, elem, ty, Args, Array, Bytes, CastInfo, Content, Finalize, FromValue, IntoValue, Label, NativeElement, Reflect, Repr, Scope, Show, Smart, Str, StyleChain, @@ -28,7 +29,7 @@ use crate::foundations::{ }; use crate::introspection::{Introspector, Locatable, Location}; use crate::layout::{ - BlockElem, Em, GridElem, HElem, PadElem, Sizing, TrackSizings, VElem, Vt, + BlockElem, Em, GridElem, HElem, PadElem, Sizing, TrackSizings, VElem, }; use crate::model::{ CitationForm, CiteGroup, Destination, FootnoteElem, HeadingElem, LinkElem, ParElem, @@ -88,7 +89,7 @@ pub struct BibliographyElem { /// Path(s) to Hayagriva `.yml` and/or BibLaTeX `.bib` files. #[required] #[parse( - let (paths, bibliography) = Bibliography::parse(vm, args)?; + let (paths, bibliography) = Bibliography::parse(engine, args)?; paths )] pub path: BibliographyPaths, @@ -120,7 +121,7 @@ pub struct BibliographyElem { /// a [CSL file](https://citationstyles.org/). Some of the styles listed /// below appear twice, once with their full name and once with a short /// alias. - #[parse(CslStyle::parse(vm, args)?)] + #[parse(CslStyle::parse(engine, args)?)] #[default(CslStyle::from_name("ieee").unwrap())] pub style: CslStyle, @@ -169,9 +170,10 @@ impl BibliographyElem { } /// Whether the bibliography contains the given key. - pub fn has(vt: &Vt, key: impl Into<PicoStr>) -> bool { + pub fn has(engine: &Engine, key: impl Into<PicoStr>) -> bool { let key = key.into(); - vt.introspector + engine + .introspector .query(&Self::elem().select()) .iter() .any(|elem| elem.to::<Self>().unwrap().bibliography().has(key)) @@ -195,7 +197,7 @@ impl BibliographyElem { } impl Synthesize for BibliographyElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_full(self.full(styles)); self.push_style(self.style(styles)); self.push_lang(TextElem::lang_in(styles)); @@ -206,7 +208,7 @@ impl Synthesize for BibliographyElem { impl Show for BibliographyElem { #[tracing::instrument(name = "BibliographyElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { const COLUMN_GUTTER: Em = Em::new(0.65); const INDENT: Em = Em::new(1.5); @@ -219,9 +221,9 @@ impl Show for BibliographyElem { seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack()); } - Ok(vt.delayed(|vt| { + Ok(engine.delayed(|engine| { let span = self.span(); - let works = Works::generate(vt.world, vt.introspector).at(span)?; + let works = Works::generate(engine.world, engine.introspector).at(span)?; let references = works .references .as_ref() @@ -316,7 +318,7 @@ pub struct Bibliography { impl Bibliography { /// Parse the bibliography argument. fn parse( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(BibliographyPaths, Bibliography)> { let Spanned { v: paths, span } = @@ -327,8 +329,8 @@ impl Bibliography { .0 .iter() .map(|path| { - let id = vm.resolve_path(path).at(span)?; - vm.world().file(id).at(span) + let id = span.resolve_path(path).at(span)?; + engine.world.file(id).at(span) }) .collect::<SourceResult<Vec<Bytes>>>()?; @@ -438,19 +440,19 @@ pub struct CslStyle { impl CslStyle { /// Parse the style argument. - pub fn parse(vm: &mut Vm, args: &mut Args) -> SourceResult<Option<CslStyle>> { + pub fn parse(engine: &mut Engine, args: &mut Args) -> SourceResult<Option<CslStyle>> { let Some(Spanned { v: string, span }) = args.named::<Spanned<EcoString>>("style")? else { return Ok(None); }; - Ok(Some(Self::parse_impl(vm, &string).at(span)?)) + Ok(Some(Self::parse_impl(engine, &string, span).at(span)?)) } /// Parse the style argument with `Smart`. pub fn parse_smart( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<Option<Smart<CslStyle>>> { let Some(Spanned { v: smart, span }) = @@ -462,13 +464,13 @@ impl CslStyle { Ok(Some(match smart { Smart::Auto => Smart::Auto, Smart::Custom(string) => { - Smart::Custom(Self::parse_impl(vm, &string).at(span)?) + Smart::Custom(Self::parse_impl(engine, &string, span).at(span)?) } })) } /// Parse internally. - fn parse_impl(vm: &mut Vm, string: &str) -> StrResult<CslStyle> { + fn parse_impl(engine: &mut Engine, string: &str, span: Span) -> StrResult<CslStyle> { let ext = Path::new(string) .extension() .and_then(OsStr::to_str) @@ -476,8 +478,8 @@ impl CslStyle { .to_lowercase(); if ext == "csl" { - let id = vm.resolve_path(string)?; - let data = vm.world().file(id)?; + let id = span.resolve_path(string)?; + let data = engine.world.file(id)?; CslStyle::from_data(&data) } else { CslStyle::from_name(string) diff --git a/crates/typst/src/model/cite.rs b/crates/typst/src/model/cite.rs index 7ead5907..3657e83d 100644 --- a/crates/typst/src/model/cite.rs +++ b/crates/typst/src/model/cite.rs @@ -1,9 +1,9 @@ use crate::diag::{bail, At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Cast, Content, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::Locatable; -use crate::layout::Vt; use crate::model::bibliography::Works; use crate::model::CslStyle; use crate::text::{Lang, Region, TextElem}; @@ -85,7 +85,7 @@ pub struct CiteElem { /// /// When set to `{auto}`, automatically use the /// [bibliography's style]($bibliography.style) for the citations. - #[parse(CslStyle::parse_smart(vm, args)?)] + #[parse(CslStyle::parse_smart(engine, args)?)] pub style: Smart<CslStyle>, /// The text language setting where the citation is. @@ -100,7 +100,7 @@ pub struct CiteElem { } impl Synthesize for CiteElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_supplement(self.supplement(styles)); self.push_form(self.form(styles)); self.push_style(self.style(styles)); @@ -143,12 +143,12 @@ pub struct CiteGroup { } impl Show for CiteGroup { - #[tracing::instrument(name = "CiteGroup::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "CiteGroup::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); let span = self.span(); - Works::generate(vt.world, vt.introspector) + Works::generate(engine.world, engine.introspector) .at(span)? .citations .get(&location) diff --git a/crates/typst/src/model/document.rs b/crates/typst/src/model/document.rs index f6ea7d24..373a1545 100644 --- a/crates/typst/src/model/document.rs +++ b/crates/typst/src/model/document.rs @@ -2,12 +2,12 @@ use comemo::Prehashed; use ecow::EcoString; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Args, Array, Construct, Content, Datetime, Smart, StyleChain, Value, }; use crate::introspection::ManualPageCounter; -use crate::layout::{Frame, LayoutRoot, PageElem, Vt}; +use crate::layout::{Frame, LayoutRoot, PageElem}; /// The root element of a document and its metadata. /// @@ -56,7 +56,7 @@ pub struct DocumentElem { } impl Construct for DocumentElem { - fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(_: &mut Engine, args: &mut Args) -> SourceResult<Content> { bail!(args.span, "can only be used in set rules") } } @@ -64,7 +64,11 @@ impl Construct for DocumentElem { impl LayoutRoot for DocumentElem { /// Layout the document into a sequence of frames, one per page. #[tracing::instrument(name = "DocumentElem::layout_root", skip_all)] - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document> { tracing::info!("Document layout"); let mut pages = vec![]; @@ -88,7 +92,8 @@ impl LayoutRoot for DocumentElem { .to::<PageElem>()? .clear_to(styles) }); - let fragment = page.layout(vt, styles, &mut page_counter, extend_to)?; + let fragment = + page.layout(engine, styles, &mut page_counter, extend_to)?; pages.extend(fragment); } else { bail!(child.span(), "unexpected document child"); diff --git a/crates/typst/src/model/emph.rs b/crates/typst/src/model/emph.rs index 1b7f654c..de7b8bef 100644 --- a/crates/typst/src/model/emph.rs +++ b/crates/typst/src/model/emph.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::Vt; use crate::text::{ItalicToggle, TextElem}; /// Emphasizes content by setting it in italics. @@ -35,7 +35,7 @@ pub struct EmphElem { impl Show for EmphElem { #[tracing::instrument(name = "EmphElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_emph(ItalicToggle))) } } diff --git a/crates/typst/src/model/enum.rs b/crates/typst/src/model/enum.rs index f440bc39..f4583f8d 100644 --- a/crates/typst/src/model/enum.rs +++ b/crates/typst/src/model/enum.rs @@ -1,12 +1,13 @@ use std::str::FromStr; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Fold, NativeElement, Smart, StyleChain, }; use crate::layout::{ Axes, BlockElem, Em, Fragment, GridLayouter, HAlign, Layout, Length, Regions, Sizing, - Spacing, VAlign, Vt, + Spacing, VAlign, }; use crate::model::{Numbering, NumberingPattern, ParElem}; use crate::text::TextElem; @@ -209,7 +210,7 @@ impl Layout for EnumElem { #[tracing::instrument(name = "EnumElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -239,7 +240,7 @@ impl Layout for EnumElem { let resolved = if full { parents.push(number); - let content = numbering.apply_vt(vt, &parents)?.display(); + let content = numbering.apply(engine, &parents)?.display(); parents.pop(); content } else { @@ -247,7 +248,7 @@ impl Layout for EnumElem { Numbering::Pattern(pattern) => { TextElem::packed(pattern.apply_kth(parents.len(), number)) } - other => other.apply_vt(vt, &[number])?.display(), + other => other.apply(engine, &[number])?.display(), } }; @@ -277,7 +278,7 @@ impl Layout for EnumElem { self.span(), ); - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } diff --git a/crates/typst/src/model/figure.rs b/crates/typst/src/model/figure.rs index 26a96db1..e6ab7a2a 100644 --- a/crates/typst/src/model/figure.rs +++ b/crates/typst/src/model/figure.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use ecow::EcoString; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Selector, Show, Smart, StyleChain, Synthesize, @@ -12,7 +13,7 @@ use crate::foundations::{ use crate::introspection::{ Count, Counter, CounterKey, CounterUpdate, Locatable, Location, }; -use crate::layout::{Align, BlockElem, Em, HAlign, Length, PlaceElem, VAlign, VElem, Vt}; +use crate::layout::{Align, BlockElem, Em, HAlign, Length, PlaceElem, VAlign, VElem}; use crate::model::{Numbering, NumberingPattern, Outlinable, Refable, Supplement}; use crate::syntax::Spanned; use crate::text::{Lang, Region, TextElem}; @@ -220,7 +221,11 @@ impl FigureElem { } impl Synthesize for FigureElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { let numbering = self.numbering(styles); // Determine the figure's kind. @@ -264,7 +269,7 @@ impl Synthesize for FigureElem { }; let target = descendant.unwrap_or_else(|| Cow::Borrowed(self.body())); - Some(supplement.resolve(vt, [target])?) + Some(supplement.resolve(engine, [target])?) } }; @@ -296,7 +301,7 @@ impl Synthesize for FigureElem { impl Show for FigureElem { #[tracing::instrument(name = "FigureElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); // Build the caption, if any. @@ -364,7 +369,7 @@ impl Refable for FigureElem { } impl Outlinable for FigureElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } @@ -384,7 +389,7 @@ impl Outlinable for FigureElem { self.numbering(StyleChain::default()), ) { let location = self.location().unwrap(); - let numbers = counter.at(vt, location)?.display(vt, &numbering)?; + let numbers = counter.at(engine, location)?.display(engine, &numbering)?; if !supplement.is_empty() { supplement += TextElem::packed('\u{a0}'); @@ -538,7 +543,7 @@ impl FigureCaption { } impl Synthesize for FigureCaption { - fn synthesize(&mut self, _: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_position(self.position(styles)); self.push_separator(Smart::Custom(self.get_separator(styles))); Ok(()) @@ -547,7 +552,7 @@ impl Synthesize for FigureCaption { impl Show for FigureCaption { #[tracing::instrument(name = "FigureCaption::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); if let (Some(mut supplement), Some(numbering), Some(counter), Some(location)) = ( @@ -556,7 +561,7 @@ impl Show for FigureCaption { self.counter(), self.figure_location(), ) { - let numbers = counter.at(vt, *location)?.display(vt, numbering)?; + let numbers = counter.at(engine, *location)?.display(engine, numbering)?; if !supplement.is_empty() { supplement += TextElem::packed('\u{a0}'); } diff --git a/crates/typst/src/model/footnote.rs b/crates/typst/src/model/footnote.rs index d51ee226..df88b58c 100644 --- a/crates/typst/src/model/footnote.rs +++ b/crates/typst/src/model/footnote.rs @@ -4,12 +4,13 @@ use std::str::FromStr; use comemo::Prehashed; use crate::diag::{bail, error, At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Location}; -use crate::layout::{Abs, Em, HElem, Length, Ratio, Vt}; +use crate::layout::{Abs, Em, HElem, Length, Ratio}; use crate::model::{Destination, Numbering, NumberingPattern, ParElem}; use crate::text::{SuperElem, TextElem, TextSize}; use crate::util::NonZeroExt; @@ -107,14 +108,15 @@ impl FootnoteElem { } /// Returns the location of the definition of this footnote. - pub fn declaration_location(&self, vt: &Vt) -> StrResult<Location> { + pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> { match self.body() { FootnoteBody::Reference(label) => { - let element: Prehashed<Content> = vt.introspector.query_label(*label)?; + let element: Prehashed<Content> = + engine.introspector.query_label(*label)?; let footnote = element .to::<FootnoteElem>() .ok_or("referenced element should be a footnote")?; - footnote.declaration_location(vt) + footnote.declaration_location(engine) } _ => Ok(self.location().unwrap()), } @@ -122,7 +124,7 @@ impl FootnoteElem { } impl Synthesize for FootnoteElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_numbering(self.numbering(styles).clone()); Ok(()) } @@ -130,12 +132,12 @@ impl Synthesize for FootnoteElem { impl Show for FootnoteElem { #[tracing::instrument(name = "FootnoteElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { - let loc = self.declaration_location(vt).at(self.span())?; + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { + let loc = self.declaration_location(engine).at(self.span())?; let numbering = self.numbering(styles); let counter = Counter::of(Self::elem()); - let num = counter.at(vt, loc)?.display(vt, numbering)?; + let num = counter.at(engine, loc)?.display(engine, numbering)?; let sup = SuperElem::new(num).pack(); let loc = loc.variant(1); // Add zero-width weak spacing to make the footnote "sticky". @@ -271,7 +273,7 @@ pub struct FootnoteEntry { } impl Show for FootnoteEntry { - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let note = self.note(); let number_gap = Em::new(0.05); let default = StyleChain::default(); @@ -283,7 +285,7 @@ impl Show for FootnoteEntry { )) }; - let num = counter.at(vt, loc)?.display(vt, numbering)?; + let num = counter.at(engine, loc)?.display(engine, numbering)?; let sup = SuperElem::new(num) .pack() .linked(Destination::Location(loc)) diff --git a/crates/typst/src/model/heading.rs b/crates/typst/src/model/heading.rs index 3365f00c..6f8932d4 100644 --- a/crates/typst/src/model/heading.rs +++ b/crates/typst/src/model/heading.rs @@ -1,12 +1,13 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Finalize, NativeElement, Show, Smart, StyleChain, Styles, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; -use crate::layout::{BlockElem, Em, HElem, VElem, Vt}; +use crate::layout::{BlockElem, Em, HElem, VElem}; use crate::model::{Numbering, Outlinable, Refable, Supplement}; use crate::text::{FontWeight, Lang, LocalName, Region, SpaceElem, TextElem, TextSize}; use crate::util::{option_eq, NonZeroExt}; @@ -126,12 +127,18 @@ pub struct HeadingElem { } impl Synthesize for HeadingElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { // Resolve the supplement. let supplement = match self.supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?, + Smart::Custom(Some(supplement)) => { + supplement.resolve(engine, [self.clone()])? + } }; self.push_level(self.level(styles)); @@ -146,7 +153,7 @@ impl Synthesize for HeadingElem { impl Show for HeadingElem { #[tracing::instrument(name = "HeadingElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); if let Some(numbering) = self.numbering(styles).as_ref() { realized = Counter::of(Self::elem()) @@ -214,7 +221,7 @@ impl Refable for HeadingElem { } impl Outlinable for HeadingElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } @@ -223,8 +230,8 @@ impl Outlinable for HeadingElem { let default = StyleChain::default(); if let Some(numbering) = self.numbering(default).as_ref() { let numbers = Counter::of(Self::elem()) - .at(vt, self.location().unwrap())? - .display(vt, numbering)?; + .at(engine, self.location().unwrap())? + .display(engine, numbering)?; content = numbers + SpaceElem::new().pack() + content; }; diff --git a/crates/typst/src/model/link.rs b/crates/typst/src/model/link.rs index 27a05737..5d1b4f19 100644 --- a/crates/typst/src/model/link.rs +++ b/crates/typst/src/model/link.rs @@ -1,11 +1,12 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Label, NativeElement, Repr, Show, Smart, StyleChain, }; use crate::introspection::Location; -use crate::layout::{Position, Vt}; +use crate::layout::Position; use crate::text::{Hyphenate, TextElem}; /// Links to a URL or a location in the document. @@ -89,14 +90,14 @@ impl LinkElem { } impl Show for LinkElem { - #[tracing::instrument(name = "LinkElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { + #[tracing::instrument(name = "LinkElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let linked = match self.dest() { LinkTarget::Dest(dest) => body.linked(dest.clone()), - LinkTarget::Label(label) => vt - .delayed(|vt| { - let elem = vt.introspector.query_label(*label).at(self.span())?; + LinkTarget::Label(label) => engine + .delayed(|engine| { + let elem = engine.introspector.query_label(*label).at(self.span())?; let dest = Destination::Location(elem.location().unwrap()); Ok(Some(body.clone().linked(dest))) }) diff --git a/crates/typst/src/model/list.rs b/crates/typst/src/model/list.rs index e9275f03..623cafa2 100644 --- a/crates/typst/src/model/list.rs +++ b/crates/typst/src/model/list.rs @@ -1,11 +1,12 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Fold, Func, NativeElement, Smart, StyleChain, Value, }; use crate::layout::{ Axes, BlockElem, Em, Fragment, GridLayouter, HAlign, Layout, Length, Regions, Sizing, - Spacing, VAlign, Vt, + Spacing, VAlign, }; use crate::model::ParElem; use crate::text::TextElem; @@ -130,7 +131,7 @@ impl Layout for ListElem { #[tracing::instrument(name = "ListElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -146,7 +147,7 @@ impl Layout for ListElem { let depth = self.depth(styles); let marker = self .marker(styles) - .resolve(vt, depth)? + .resolve(engine, depth)? // avoid '#set align' interference with the list .aligned(HAlign::Start + VAlign::Top); @@ -172,7 +173,7 @@ impl Layout for ListElem { self.span(), ); - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } @@ -198,12 +199,12 @@ pub enum ListMarker { impl ListMarker { /// Resolve the marker for the given depth. - fn resolve(&self, vt: &mut Vt, depth: usize) -> SourceResult<Content> { + fn resolve(&self, engine: &mut Engine, depth: usize) -> SourceResult<Content> { Ok(match self { Self::Content(list) => { list.get(depth).or(list.last()).cloned().unwrap_or_default() } - Self::Func(func) => func.call_vt(vt, [depth])?.display(), + Self::Func(func) => func.call(engine, [depth])?.display(), }) } } diff --git a/crates/typst/src/model/numbering.rs b/crates/typst/src/model/numbering.rs index fa7a88c4..d91a5c52 100644 --- a/crates/typst/src/model/numbering.rs +++ b/crates/typst/src/model/numbering.rs @@ -5,9 +5,9 @@ use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToCh use ecow::{eco_format, EcoString, EcoVec}; use crate::diag::SourceResult; -use crate::eval::Vm; -use crate::foundations::{cast, func, Args, Func, Str, Value}; -use crate::layout::{PdfPageLabel, PdfPageLabelStyle, Vt}; +use crate::engine::Engine; +use crate::foundations::{cast, func, Func, Str, Value}; +use crate::layout::{PdfPageLabel, PdfPageLabelStyle}; use crate::text::Case; /// Applies a numbering to a sequence of numbers. @@ -35,8 +35,8 @@ use crate::text::Case; /// ``` #[func] pub fn numbering( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Defines how the numbering works. /// /// **Counting symbols** are `1`, `a`, `A`, `i`, `I`, `い`, `イ`, `א`, `가`, @@ -68,7 +68,7 @@ pub fn numbering( #[variadic] numbers: Vec<usize>, ) -> SourceResult<Value> { - numbering.apply_vm(vm, &numbers) + numbering.apply(engine, &numbers) } /// How to number a sequence of things. @@ -82,21 +82,10 @@ pub enum Numbering { impl Numbering { /// Apply the pattern to the given numbers. - pub fn apply_vm(&self, vm: &mut Vm, numbers: &[usize]) -> SourceResult<Value> { + pub fn apply(&self, engine: &mut Engine, numbers: &[usize]) -> SourceResult<Value> { Ok(match self { Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()), - Self::Func(func) => { - let args = Args::new(func.span(), numbers.iter().copied()); - func.call_vm(vm, args)? - } - }) - } - - /// Apply the pattern to the given numbers. - pub fn apply_vt(&self, vt: &mut Vt, numbers: &[usize]) -> SourceResult<Value> { - Ok(match self { - Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()), - Self::Func(func) => func.call_vt(vt, numbers.iter().copied())?, + Self::Func(func) => func.call(engine, numbers.iter().copied())?, }) } diff --git a/crates/typst/src/model/outline.rs b/crates/typst/src/model/outline.rs index 3b23098e..91526a9c 100644 --- a/crates/typst/src/model/outline.rs +++ b/crates/typst/src/model/outline.rs @@ -2,12 +2,13 @@ use std::num::NonZeroUsize; use std::str::FromStr; use crate::diag::{bail, error, At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Finalize, Func, LocatableSelector, NativeElement, Show, Smart, StyleChain, }; use crate::introspection::{Counter, CounterKey, Locatable}; -use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing, Vt}; +use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing}; use crate::model::{Destination, HeadingElem, NumberingPattern, ParbreakElem, Refable}; use crate::syntax::Span; use crate::text::{Lang, LinebreakElem, LocalName, Region, SpaceElem, TextElem}; @@ -186,7 +187,7 @@ impl OutlineElem { impl Show for OutlineElem { #[tracing::instrument(name = "OutlineElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut seq = vec![ParbreakElem::new().pack()]; // Build the outline title. if let Some(title) = self.title(styles) { @@ -201,11 +202,11 @@ impl Show for OutlineElem { let depth = self.depth(styles).unwrap_or(NonZeroUsize::new(usize::MAX).unwrap()); let mut ancestors: Vec<&Content> = vec![]; - let elems = vt.introspector.query(&self.target(styles).0); + let elems = engine.introspector.query(&self.target(styles).0); for elem in &elems { let Some(entry) = OutlineEntry::from_outlinable( - vt, + engine, self.span(), elem.clone().into_inner(), self.fill(styles), @@ -229,7 +230,7 @@ impl Show for OutlineElem { ancestors.pop(); } - OutlineIndent::apply(indent, vt, &ancestors, &mut seq, self.span())?; + OutlineIndent::apply(indent, engine, &ancestors, &mut seq, self.span())?; // Add the overridable outline entry, followed by a line break. seq.push(entry.pack()); @@ -292,7 +293,7 @@ impl LocalName for OutlineElem { /// `#outline()` element. pub trait Outlinable: Refable { /// Produce an outline item for this element. - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>>; + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>>; /// Returns the nesting level of this element. fn level(&self) -> NonZeroUsize { @@ -311,7 +312,7 @@ pub enum OutlineIndent { impl OutlineIndent { fn apply( indent: &Option<Smart<Self>>, - vt: &mut Vt, + engine: &mut Engine, ancestors: &Vec<&Content>, seq: &mut Vec<Content>, span: Span, @@ -330,8 +331,8 @@ impl OutlineIndent { if let Some(numbering) = ancestor_outlinable.numbering() { let numbers = ancestor_outlinable .counter() - .at(vt, ancestor.location().unwrap())? - .display(vt, &numbering)?; + .at(engine, ancestor.location().unwrap())? + .display(engine, &numbering)?; hidden += numbers + SpaceElem::new().pack(); }; @@ -355,7 +356,7 @@ impl OutlineIndent { Some(Smart::Custom(OutlineIndent::Func(func))) => { let depth = ancestors.len(); let LengthOrContent(content) = - func.call_vt(vt, [depth])?.cast().at(span)?; + func.call(engine, [depth])?.cast().at(span)?; if !content.is_empty() { seq.push(content); } @@ -455,7 +456,7 @@ impl OutlineEntry { /// be outlined (e.g. heading with 'outlined: false'), does not generate an /// entry instance (returns `Ok(None)`). fn from_outlinable( - vt: &mut Vt, + engine: &mut Engine, span: Span, elem: Content, fill: Option<Content>, @@ -464,27 +465,27 @@ impl OutlineEntry { bail!(span, "cannot outline {}", elem.func().name()); }; - let Some(body) = outlinable.outline(vt)? else { + let Some(body) = outlinable.outline(engine)? else { return Ok(None); }; let location = elem.location().unwrap(); - let page_numbering = vt + let page_numbering = engine .introspector .page_numbering(location) .cloned() .unwrap_or_else(|| NumberingPattern::from_str("1").unwrap().into()); let page = Counter::new(CounterKey::Page) - .at(vt, location)? - .display(vt, &page_numbering)?; + .at(engine, location)? + .display(engine, &page_numbering)?; Ok(Some(Self::new(outlinable.level(), elem, body, fill, page))) } } impl Show for OutlineEntry { - fn show(&self, _vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { let mut seq = vec![]; let elem = self.element(); diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs index 84274661..c9f64efb 100644 --- a/crates/typst/src/model/par.rs +++ b/crates/typst/src/model/par.rs @@ -1,12 +1,12 @@ use comemo::Prehashed; use crate::diag::SourceResult; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ elem, Args, Cast, Construct, Content, NativeElement, Set, Smart, StyleChain, Unlabellable, }; -use crate::layout::{Em, Fragment, Length, Size, Vt}; +use crate::layout::{Em, Fragment, Length, Size}; /// Arranges text, spacing and inline-level elements into a paragraph. /// @@ -108,11 +108,11 @@ pub struct ParElem { } impl Construct for ParElem { - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> { // The paragraph constructor is special: It doesn't create a paragraph // element. Instead, it just ensures that the passed content lives in a // separate paragraph and styles it. - let styles = Self::set(vm, args)?; + let styles = Self::set(engine, args)?; let body = args.expect::<Content>("body")?; Ok(Content::sequence([ ParbreakElem::new().pack(), @@ -127,7 +127,7 @@ impl ParElem { #[tracing::instrument(name = "ParElement::layout", skip_all)] pub fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, consecutive: bool, region: Size, @@ -135,7 +135,7 @@ impl ParElem { ) -> SourceResult<Fragment> { crate::layout::layout_inline( self.children(), - vt, + engine, styles, consecutive, region, diff --git a/crates/typst/src/model/quote.rs b/crates/typst/src/model/quote.rs index 489e2657..2a709071 100644 --- a/crates/typst/src/model/quote.rs +++ b/crates/typst/src/model/quote.rs @@ -1,9 +1,10 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; -use crate::layout::{Align, BlockElem, Em, HElem, PadElem, Spacing, VElem, Vt}; +use crate::layout::{Align, BlockElem, Em, HElem, PadElem, Spacing, VElem}; use crate::model::{CitationForm, CiteElem}; use crate::text::{SmartQuoteElem, SpaceElem, TextElem}; @@ -145,7 +146,7 @@ cast! { } impl Synthesize for QuoteElem { - fn synthesize(&mut self, _: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_block(self.block(styles)); self.push_quotes(self.quotes(styles)); Ok(()) @@ -153,7 +154,7 @@ impl Synthesize for QuoteElem { } impl Show for QuoteElem { - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); let block = self.block(styles); diff --git a/crates/typst/src/model/reference.rs b/crates/typst/src/model/reference.rs index 7f328e28..d64de1ae 100644 --- a/crates/typst/src/model/reference.rs +++ b/crates/typst/src/model/reference.rs @@ -1,12 +1,12 @@ use ecow::eco_format; use crate::diag::{bail, At, Hint, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Func, IntoValue, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::{Counter, Locatable}; -use crate::layout::Vt; use crate::math::EquationElem; use crate::model::{ BibliographyElem, CiteElem, Destination, Figurable, FootnoteElem, Numbering, @@ -137,14 +137,18 @@ pub struct RefElem { } impl Synthesize for RefElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { - let citation = self.to_citation(vt, styles)?; + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { + let citation = self.to_citation(engine, styles)?; self.push_citation(Some(citation)); self.push_element(None); let target = *self.target(); - if !BibliographyElem::has(vt, target) { - if let Ok(elem) = vt.introspector.query_label(target) { + if !BibliographyElem::has(engine, target) { + if let Ok(elem) = engine.introspector.query_label(target) { self.push_element(Some(elem.into_inner())); return Ok(()); } @@ -156,18 +160,18 @@ impl Synthesize for RefElem { impl Show for RefElem { #[tracing::instrument(name = "RefElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let target = *self.target(); - let elem = vt.introspector.query_label(target); + let elem = engine.introspector.query_label(target); let span = self.span(); - if BibliographyElem::has(vt, target) { + if BibliographyElem::has(engine, target) { if elem.is_ok() { bail!(span, "label occurs in the document and its bibliography"); } - return Ok(self.to_citation(vt, styles)?.spanned(span).pack()); + return Ok(self.to_citation(engine, styles)?.spanned(span).pack()); } let elem = elem.at(span)?; @@ -211,14 +215,14 @@ impl Show for RefElem { let numbers = refable .counter() - .at(vt, elem.location().unwrap())? - .display(vt, &numbering.trimmed())?; + .at(engine, elem.location().unwrap())? + .display(engine, &numbering.trimmed())?; let supplement = match self.supplement(styles).as_ref() { Smart::Auto => refable.supplement(), Smart::Custom(None) => Content::empty(), Smart::Custom(Some(supplement)) => { - supplement.resolve(vt, [(*elem).clone()])? + supplement.resolve(engine, [(*elem).clone()])? } }; @@ -234,10 +238,14 @@ impl Show for RefElem { impl RefElem { /// Turn the reference into a citation. - pub fn to_citation(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<CiteElem> { + pub fn to_citation( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<CiteElem> { let mut elem = CiteElem::new(*self.target()); elem.set_location(self.location().unwrap()); - elem.synthesize(vt, styles)?; + elem.synthesize(engine, styles)?; elem.push_supplement(match self.supplement(styles).clone() { Smart::Custom(Some(Supplement::Content(content))) => Some(content), _ => None, @@ -258,12 +266,12 @@ impl Supplement { /// Tries to resolve the supplement into its content. pub fn resolve<T: IntoValue>( &self, - vt: &mut Vt, + engine: &mut Engine, args: impl IntoIterator<Item = T>, ) -> SourceResult<Content> { Ok(match self { Supplement::Content(content) => content.clone(), - Supplement::Func(func) => func.call_vt(vt, args)?.display(), + Supplement::Func(func) => func.call(engine, args)?.display(), }) } } diff --git a/crates/typst/src/model/strong.rs b/crates/typst/src/model/strong.rs index 40b99b2f..666a4aa0 100644 --- a/crates/typst/src/model/strong.rs +++ b/crates/typst/src/model/strong.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::Vt; use crate::text::{TextElem, WeightDelta}; /// Strongly emphasizes content by increasing the font weight. @@ -39,7 +39,7 @@ pub struct StrongElem { impl Show for StrongElem { #[tracing::instrument(name = "StrongElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() .clone() diff --git a/crates/typst/src/model/table.rs b/crates/typst/src/model/table.rs index 278b898c..31c6636f 100644 --- a/crates/typst/src/model/table.rs +++ b/crates/typst/src/model/table.rs @@ -1,11 +1,12 @@ use crate::diag::{At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Array, CastInfo, Content, FromValue, Func, IntoValue, NativeElement, Reflect, Smart, StyleChain, Value, }; use crate::layout::{ Abs, Align, AlignElem, Axes, Fragment, FrameItem, GridLayouter, Layout, Length, - Point, Regions, Rel, Sides, Size, TrackSizings, Vt, + Point, Regions, Rel, Sides, Size, TrackSizings, }; use crate::model::Figurable; use crate::text::{Lang, LocalName, Region}; @@ -158,7 +159,7 @@ impl Layout for TableElem { #[tracing::instrument(name = "TableElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -181,7 +182,7 @@ impl Layout for TableElem { let x = i % cols; let y = i / cols; - if let Smart::Custom(alignment) = align.resolve(vt, x, y)? { + if let Smart::Custom(alignment) = align.resolve(engine, x, y)? { child = child.styled(AlignElem::set_alignment(alignment)); } @@ -197,7 +198,7 @@ impl Layout for TableElem { GridLayouter::new(tracks, gutter, &cells, regions, styles, self.span()); // Measure the columns and layout the grid row-by-row. - let mut layout = layouter.layout(vt)?; + let mut layout = layouter.layout(engine)?; // Add lines and backgrounds. for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) { @@ -236,7 +237,7 @@ impl Layout for TableElem { for (x, &col) in layout.cols.iter().enumerate() { let mut dy = Abs::zero(); for row in rows { - if let Some(fill) = fill.resolve(vt, x, row.y)? { + if let Some(fill) = fill.resolve(engine, x, row.y)? { let pos = Point::new(dx, dy); let size = Size::new(col, row.height); let rect = Geometry::Rect(size).filled(fill); @@ -275,10 +276,10 @@ pub enum Celled<T> { impl<T: Default + Clone + FromValue> Celled<T> { /// Resolve the value based on the cell position. - pub fn resolve(&self, vt: &mut Vt, x: usize, y: usize) -> SourceResult<T> { + pub fn resolve(&self, engine: &mut Engine, x: usize, y: usize) -> SourceResult<T> { Ok(match self { Self::Value(value) => value.clone(), - Self::Func(func) => func.call_vt(vt, [x, y])?.cast().at(func.span())?, + Self::Func(func) => func.call(engine, [x, y])?.cast().at(func.span())?, Self::Array(array) => x .checked_rem(array.len()) .and_then(|i| array.get(i)) diff --git a/crates/typst/src/model/terms.rs b/crates/typst/src/model/terms.rs index 1d256626..bbb6129a 100644 --- a/crates/typst/src/model/terms.rs +++ b/crates/typst/src/model/terms.rs @@ -1,9 +1,10 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, NativeElement, Smart, StyleChain, }; use crate::layout::{ - BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem, Vt, + BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem, }; use crate::model::ParElem; use crate::util::Numeric; @@ -110,7 +111,7 @@ impl Layout for TermsElem { #[tracing::instrument(name = "TermsElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -139,7 +140,7 @@ impl Layout for TermsElem { Content::sequence(seq) .styled(ParElem::set_hanging_indent(hanging_indent + indent)) - .layout(vt, styles, regions) + .layout(engine, styles, regions) } } diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs index 2b5ce22d..c2f19303 100644 --- a/crates/typst/src/realize/mod.rs +++ b/crates/typst/src/realize/mod.rs @@ -10,7 +10,8 @@ use std::mem; use smallvec::smallvec; use typed_arena::Arena; -use crate::diag::{bail, SourceResult}; +use crate::diag::{bail, error, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain, StyleVecBuilder, Styles, Synthesize, @@ -18,7 +19,7 @@ use crate::foundations::{ use crate::introspection::{Locatable, Meta, MetaElem}; use crate::layout::{ AlignElem, BlockElem, BoxElem, ColbreakElem, FlowElem, HElem, Layout, LayoutRoot, - PageElem, PagebreakElem, Parity, PlaceElem, VElem, Vt, + PageElem, PagebreakElem, Parity, PlaceElem, VElem, }; use crate::math::{EquationElem, LayoutMath}; use crate::model::{ @@ -33,6 +34,58 @@ use crate::visualize::{ SquareElem, }; +/// Realize into an element that is capable of root-level layout. +#[tracing::instrument(skip_all)] +pub fn realize_root<'a>( + engine: &mut Engine, + scratch: &'a Scratch<'a>, + content: &'a Content, + styles: StyleChain<'a>, +) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { + if content.can::<dyn LayoutRoot>() && !applicable(content, styles) { + return Ok((Cow::Borrowed(content), styles)); + } + + let mut builder = Builder::new(engine, scratch, true); + builder.accept(content, styles)?; + builder.interrupt_page(Some(styles), true)?; + let (pages, shared) = builder.doc.unwrap().pages.finish(); + Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack()), shared)) +} + +/// Realize into an element that is capable of block-level layout. +#[tracing::instrument(skip_all)] +pub fn realize_block<'a>( + engine: &mut Engine, + scratch: &'a Scratch<'a>, + content: &'a Content, + styles: StyleChain<'a>, +) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { + // These elements implement `Layout` but still require a flow for + // proper layout. + if content.can::<dyn Layout>() + && !content.is::<BoxElem>() + && !content.is::<LineElem>() + && !content.is::<RectElem>() + && !content.is::<SquareElem>() + && !content.is::<EllipseElem>() + && !content.is::<CircleElem>() + && !content.is::<ImageElem>() + && !content.is::<PolygonElem>() + && !content.is::<PathElem>() + && !content.is::<PlaceElem>() + && !applicable(content, styles) + { + return Ok((Cow::Borrowed(content), styles)); + } + + let mut builder = Builder::new(engine, scratch, false); + builder.accept(content, styles)?; + builder.interrupt_par()?; + let (children, shared) = builder.flow.0.finish(); + Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack()), shared)) +} + /// Whether the target is affected by show rules in the given style chain. pub fn applicable(target: &Content, styles: StyleChain) -> bool { if target.needs_preparation() { @@ -59,7 +112,7 @@ pub fn applicable(target: &Content, styles: StyleChain) -> bool { /// Apply the show rules in the given style chain to a target. pub fn realize( - vt: &mut Vt, + engine: &mut Engine, target: &Content, styles: StyleChain, ) -> SourceResult<Option<Content>> { @@ -67,12 +120,12 @@ pub fn realize( if target.needs_preparation() { let mut elem = target.clone(); if target.can::<dyn Locatable>() || target.label().is_some() { - let location = vt.locator.locate(hash128(target)); + let location = engine.locator.locate(hash128(target)); elem.set_location(location); } if let Some(elem) = elem.with_mut::<dyn Synthesize>() { - elem.synthesize(vt, styles)?; + elem.synthesize(engine, styles)?; } elem.mark_prepared(); @@ -97,7 +150,7 @@ pub fn realize( for recipe in styles.recipes() { let guard = Guard::Nth(n); if recipe.applicable(target) && !target.is_guarded(guard) { - if let Some(content) = try_apply(vt, target, recipe, guard)? { + if let Some(content) = try_apply(engine, target, recipe, guard)? { realized = Some(content); break; } @@ -109,7 +162,7 @@ pub fn realize( if let Some(showable) = target.with::<dyn Show>() { let guard = Guard::Base(target.func()); if realized.is_none() && !target.is_guarded(guard) { - realized = Some(showable.show(vt, styles)?); + realized = Some(showable.show(engine, styles)?); } } @@ -127,7 +180,7 @@ pub fn realize( /// Try to apply a recipe to the target. fn try_apply( - vt: &mut Vt, + engine: &mut Engine, target: &Content, recipe: &Recipe, guard: Guard, @@ -138,7 +191,7 @@ fn try_apply( return Ok(None); } - recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some) + recipe.apply(engine, target.clone().guarded(guard)).map(Some) } Some(Selector::Label(label)) => { @@ -146,7 +199,7 @@ fn try_apply( return Ok(None); } - recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some) + recipe.apply(engine, target.clone().guarded(guard)).map(Some) } Some(Selector::Regex(regex)) => { @@ -172,7 +225,7 @@ fn try_apply( } let piece = make(m.as_str()).guarded(guard); - let transformed = recipe.apply_vt(vt, piece)?; + let transformed = recipe.apply(engine, piece)?; result.push(transformed); cursor = m.end(); } @@ -202,62 +255,10 @@ fn try_apply( } } -/// Realize into an element that is capable of root-level layout. -#[tracing::instrument(skip_all)] -pub fn realize_root<'a>( - vt: &mut Vt, - scratch: &'a Scratch<'a>, - content: &'a Content, - styles: StyleChain<'a>, -) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { - if content.can::<dyn LayoutRoot>() && !applicable(content, styles) { - return Ok((Cow::Borrowed(content), styles)); - } - - let mut builder = Builder::new(vt, scratch, true); - builder.accept(content, styles)?; - builder.interrupt_page(Some(styles), true)?; - let (pages, shared) = builder.doc.unwrap().pages.finish(); - Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack()), shared)) -} - -/// Realize into an element that is capable of block-level layout. -#[tracing::instrument(skip_all)] -pub fn realize_block<'a>( - vt: &mut Vt, - scratch: &'a Scratch<'a>, - content: &'a Content, - styles: StyleChain<'a>, -) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { - // These elements implement `Layout` but still require a flow for - // proper layout. - if content.can::<dyn Layout>() - && !content.is::<BoxElem>() - && !content.is::<LineElem>() - && !content.is::<RectElem>() - && !content.is::<SquareElem>() - && !content.is::<EllipseElem>() - && !content.is::<CircleElem>() - && !content.is::<ImageElem>() - && !content.is::<PolygonElem>() - && !content.is::<PathElem>() - && !content.is::<PlaceElem>() - && !applicable(content, styles) - { - return Ok((Cow::Borrowed(content), styles)); - } - - let mut builder = Builder::new(vt, scratch, false); - builder.accept(content, styles)?; - builder.interrupt_par()?; - let (children, shared) = builder.flow.0.finish(); - Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack()), shared)) -} - /// Builds a document or a flow element from content. struct Builder<'a, 'v, 't> { - /// The virtual typesetter. - vt: &'v mut Vt<'t>, + /// The engine. + engine: &'v mut Engine<'t>, /// Scratch arenas for building. scratch: &'a Scratch<'a>, /// The current document building state. @@ -282,9 +283,9 @@ pub struct Scratch<'a> { } impl<'a, 'v, 't> Builder<'a, 'v, 't> { - fn new(vt: &'v mut Vt<'t>, scratch: &'a Scratch<'a>, top: bool) -> Self { + fn new(engine: &'v mut Engine<'t>, scratch: &'a Scratch<'a>, top: bool) -> Self { Self { - vt, + engine, scratch, doc: top.then(DocBuilder::default), flow: FlowBuilder::default(), @@ -304,9 +305,19 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { self.scratch.content.alloc(EquationElem::new(content.clone()).pack()); } - if let Some(realized) = realize(self.vt, content, styles)? { + if let Some(realized) = realize(self.engine, content, styles)? { + self.engine.route.increase(); + if self.engine.route.exceeding() { + bail!(error!(content.span(), "maximum show rule depth exceeded") + .with_hint("check whether the show rule matches its own output") + .with_hint( + "this is a current compiler limitation that will be resolved in the future" + )); + } let stored = self.scratch.content.alloc(realized); - return self.accept(stored, styles); + let v = self.accept(stored, styles); + self.engine.route.decrease(); + return v; } if let Some((elem, local)) = content.to_styled() { diff --git a/crates/typst/src/text/deco.rs b/crates/typst/src/text/deco.rs index f7ee8cbc..348ddf34 100644 --- a/crates/typst/src/text/deco.rs +++ b/crates/typst/src/text/deco.rs @@ -4,8 +4,9 @@ use ttf_parser::{GlyphId, OutlineBuilder}; use ecow::{eco_format, EcoString}; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{cast, elem, ty, Content, Fold, Repr, Show, Smart, StyleChain}; -use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size, Vt}; +use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size}; use crate::syntax::Span; use crate::text::{ BottomEdge, BottomEdgeMetric, TextElem, TextItem, TopEdge, TopEdgeMetric, @@ -85,7 +86,7 @@ pub struct UnderlineElem { impl Show for UnderlineElem { #[tracing::instrument(name = "UnderlineElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Underline { stroke: self.stroke(styles).unwrap_or_default(), @@ -177,7 +178,7 @@ pub struct OverlineElem { impl Show for OverlineElem { #[tracing::instrument(name = "OverlineElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Overline { stroke: self.stroke(styles).unwrap_or_default(), @@ -254,7 +255,7 @@ pub struct StrikeElem { impl Show for StrikeElem { #[tracing::instrument(name = "StrikeElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { // Note that we do not support evade option for strikethrough. line: DecoLine::Strikethrough { @@ -324,7 +325,7 @@ pub struct HighlightElem { impl Show for HighlightElem { #[tracing::instrument(name = "HighlightElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Highlight { fill: self.fill(styles), diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs index 45de35f9..da3580a5 100644 --- a/crates/typst/src/text/mod.rs +++ b/crates/typst/src/text/mod.rs @@ -35,7 +35,7 @@ use rustybuzz::{Feature, Tag}; use ttf_parser::Rect; use crate::diag::{bail, error, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, category, elem, Args, Array, Cast, Category, Construct, Content, Dict, Fold, NativeElement, Never, PlainText, Repr, Resolve, Scope, Set, Smart, StyleChain, Value, @@ -656,11 +656,11 @@ impl Repr for TextElem { } impl Construct for TextElem { - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> { // The text constructor is special: It doesn't create a text element. // Instead, it leaves the passed argument structurally unchanged, but // styles all text in it. - let styles = Self::set(vm, args)?; + let styles = Self::set(engine, args)?; let body = args.expect::<Content>("body")?; Ok(body.styled_with_map(styles)) } diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs index 1142281c..6962dbce 100644 --- a/crates/typst/src/text/raw.rs +++ b/crates/typst/src/text/raw.rs @@ -10,12 +10,12 @@ use syntect::parsing::{SyntaxDefinition, SyntaxSet, SyntaxSetBuilder}; use unicode_segmentation::UnicodeSegmentation; use crate::diag::{At, FileError, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Args, Array, Bytes, Content, Finalize, Fold, NativeElement, PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value, }; -use crate::layout::{BlockElem, Em, HAlign, Vt}; +use crate::layout::{BlockElem, Em, HAlign}; use crate::model::Figurable; use crate::syntax::{split_newlines, LinkedNode, Spanned}; use crate::text::{ @@ -191,7 +191,7 @@ pub struct RawElem { /// ``` /// ```` #[parse( - let (syntaxes, syntaxes_data) = parse_syntaxes(vm, args)?; + let (syntaxes, syntaxes_data) = parse_syntaxes(engine, args)?; syntaxes )] #[fold] @@ -229,7 +229,7 @@ pub struct RawElem { /// ``` /// ```` #[parse( - let (theme_path, theme_data) = parse_theme(vm, args)?; + let (theme_path, theme_data) = parse_theme(engine, args)?; theme_path.map(Some) )] #[borrowed] @@ -288,7 +288,7 @@ impl RawElem { } impl Synthesize for RawElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_lang(self.lang(styles).clone()); let mut text = self.text().clone(); @@ -393,7 +393,7 @@ impl Synthesize for RawElem { impl Show for RawElem { #[tracing::instrument(name = "RawElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1)); for (i, line) in self.lines().iter().enumerate() { if i != 0 { @@ -495,7 +495,7 @@ pub struct RawLine { } impl Show for RawLine { - fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone()) } } @@ -676,7 +676,7 @@ fn load_syntaxes(paths: &SyntaxPaths, bytes: &[Bytes]) -> StrResult<Arc<SyntaxSe /// Function to parse the syntaxes argument. /// Much nicer than having it be part of the `element` macro. fn parse_syntaxes( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(Option<SyntaxPaths>, Option<Vec<Bytes>>)> { let Some(Spanned { v: paths, span }) = @@ -690,8 +690,8 @@ fn parse_syntaxes( .0 .iter() .map(|path| { - let id = vm.resolve_path(path).at(span)?; - vm.world().file(id).at(span) + let id = span.resolve_path(path).at(span)?; + engine.world.file(id).at(span) }) .collect::<SourceResult<Vec<Bytes>>>()?; @@ -713,7 +713,7 @@ fn load_theme(path: &str, bytes: &Bytes) -> StrResult<Arc<synt::Theme>> { /// Function to parse the theme argument. /// Much nicer than having it be part of the `element` macro. fn parse_theme( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(Option<EcoString>, Option<Bytes>)> { let Some(Spanned { v: path, span }) = args.named::<Spanned<EcoString>>("theme")? @@ -722,8 +722,8 @@ fn parse_theme( }; // Load theme file. - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; // Check that parsing works. let _ = load_theme(&path, &data).at(span)?; diff --git a/crates/typst/src/text/shift.rs b/crates/typst/src/text/shift.rs index 73f28343..e467d6c0 100644 --- a/crates/typst/src/text/shift.rs +++ b/crates/typst/src/text/shift.rs @@ -1,8 +1,9 @@ use ecow::EcoString; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::{Em, Length, Vt}; +use crate::layout::{Em, Length}; use crate::text::{variant, SpaceElem, TextElem, TextSize}; use crate::World; @@ -48,12 +49,12 @@ pub struct SubElem { impl Show for SubElem { #[tracing::instrument(name = "SubElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, true) { - if is_shapable(vt, &text, styles) { + if is_shapable(engine, &text, styles) { transformed = Some(TextElem::packed(text)); } } @@ -108,12 +109,12 @@ pub struct SuperElem { impl Show for SuperElem { #[tracing::instrument(name = "SuperElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, false) { - if is_shapable(vt, &text, styles) { + if is_shapable(engine, &text, styles) { transformed = Some(TextElem::packed(text)); } } @@ -149,8 +150,8 @@ fn search_text(content: &Content, sub: bool) -> Option<EcoString> { /// Checks whether the first retrievable family contains all code points of the /// given string. -fn is_shapable(vt: &Vt, text: &str, styles: StyleChain) -> bool { - let world = vt.world; +fn is_shapable(engine: &Engine, text: &str, styles: StyleChain) -> bool { + let world = engine.world; for family in TextElem::font_in(styles) { if let Some(font) = world .book() diff --git a/crates/typst/src/visualize/image/mod.rs b/crates/typst/src/visualize/image/mod.rs index 722e77a6..159dc14a 100644 --- a/crates/typst/src/visualize/image/mod.rs +++ b/crates/typst/src/visualize/image/mod.rs @@ -14,13 +14,14 @@ use comemo::{Prehashed, Tracked}; use ecow::EcoString; use crate::diag::{bail, At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Resolve, Smart, StyleChain, }; use crate::layout::{ Abs, Axes, FixedAlign, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, - Rel, Size, Vt, + Rel, Size, }; use crate::loading::Readable; use crate::model::Figurable; @@ -57,8 +58,8 @@ pub struct ImageElem { #[parse( let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to image file")?; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; path )] #[borrowed] @@ -145,7 +146,7 @@ impl Layout for ImageElem { #[tracing::instrument(name = "ImageElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -181,7 +182,7 @@ impl Layout for ImageElem { data.clone().into(), format, self.alt(styles), - vt.world, + engine.world, &families(styles).map(|s| s.into()).collect::<Vec<_>>(), ) .at(self.span())?; diff --git a/crates/typst/src/visualize/line.rs b/crates/typst/src/visualize/line.rs index 118395ec..ece93727 100644 --- a/crates/typst/src/visualize/line.rs +++ b/crates/typst/src/visualize/line.rs @@ -1,7 +1,8 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, NativeElement, StyleChain}; use crate::layout::{ - Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size, Vt, + Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size, }; use crate::util::Numeric; use crate::visualize::{Geometry, Stroke}; @@ -61,7 +62,7 @@ impl Layout for LineElem { #[tracing::instrument(name = "LineElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/path.rs b/crates/typst/src/visualize/path.rs index f2e1466f..6ed07cb2 100644 --- a/crates/typst/src/visualize/path.rs +++ b/crates/typst/src/visualize/path.rs @@ -1,11 +1,12 @@ use kurbo::{CubicBez, ParamCurveExtrema}; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ array, cast, elem, Array, NativeElement, Reflect, Resolve, Smart, StyleChain, }; use crate::layout::{ - Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size, Vt, + Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size, }; use crate::visualize::{FixedStroke, Geometry, Paint, Shape, Stroke}; @@ -73,7 +74,7 @@ impl Layout for PathElem { #[tracing::instrument(name = "PathElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/pattern.rs b/crates/typst/src/visualize/pattern.rs index 55d68500..3014a8e0 100644 --- a/crates/typst/src/visualize/pattern.rs +++ b/crates/typst/src/visualize/pattern.rs @@ -5,7 +5,7 @@ use comemo::Prehashed; use ecow::{eco_format, EcoString}; use crate::diag::{bail, error, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, ty, Content, Repr, Smart, StyleChain}; use crate::layout::{Abs, Axes, Em, Frame, Layout, Length, Regions, Size}; use crate::syntax::{Span, Spanned}; @@ -120,7 +120,7 @@ impl Pattern { /// ``` #[func(constructor)] pub fn construct( - vm: &mut Vm, + engine: &mut Engine, /// The bounding box of each cell of the pattern. #[named] #[default(Spanned::new(Smart::Auto, Span::detached()))] @@ -173,11 +173,11 @@ impl Pattern { let region = size.unwrap_or_else(|| Axes::splat(Abs::inf())); // Layout the pattern. - let world = vm.vt.world; + let world = engine.world; let library = world.library(); let styles = StyleChain::new(&library.styles); let pod = Regions::one(region, Axes::splat(false)); - let mut frame = body.layout(&mut vm.vt, styles, pod)?.into_frame(); + let mut frame = body.layout(engine, styles, pod)?.into_frame(); // Check that the frame is non-zero. if size.is_auto() && frame.size().is_zero() { diff --git a/crates/typst/src/visualize/polygon.rs b/crates/typst/src/visualize/polygon.rs index 3b818fa4..7436f63e 100644 --- a/crates/typst/src/visualize/polygon.rs +++ b/crates/typst/src/visualize/polygon.rs @@ -1,11 +1,12 @@ use std::f64::consts::PI; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, func, scope, Content, NativeElement, Resolve, Smart, StyleChain, }; use crate::layout::{ - Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Vt, + Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, }; use crate::util::Numeric; use crate::visualize::{FixedStroke, Geometry, Paint, Path, Shape, Stroke}; @@ -125,7 +126,7 @@ impl Layout for PolygonElem { #[tracing::instrument(name = "PolygonElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/shape.rs b/crates/typst/src/visualize/shape.rs index d1a2a155..fcdcfc31 100644 --- a/crates/typst/src/visualize/shape.rs +++ b/crates/typst/src/visualize/shape.rs @@ -1,10 +1,11 @@ use std::f64::consts::SQRT_2; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; use crate::layout::{ Abs, Axes, Corner, Corners, Fragment, Frame, FrameItem, Layout, Length, Point, Ratio, - Regions, Rel, Sides, Size, Vt, + Regions, Rel, Sides, Size, }; use crate::syntax::Span; use crate::util::Get; @@ -134,12 +135,12 @@ impl Layout for RectElem { #[tracing::instrument(name = "RectElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Rect, @@ -240,12 +241,12 @@ impl Layout for SquareElem { #[tracing::instrument(name = "SquareElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Square, @@ -318,12 +319,12 @@ impl Layout for EllipseElem { #[tracing::instrument(name = "EllipseElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Ellipse, @@ -421,12 +422,12 @@ impl Layout for CircleElem { #[tracing::instrument(name = "CircleElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Circle, @@ -446,7 +447,7 @@ impl Layout for CircleElem { #[tracing::instrument(name = "shape::layout", skip_all)] #[allow(clippy::too_many_arguments)] fn layout( - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, kind: ShapeKind, @@ -473,7 +474,7 @@ fn layout( let child = child.clone().padded(inset.map(|side| side.map(Length::from))); let expand = sizing.as_ref().map(Smart::is_custom); let pod = Regions::one(region, expand); - frame = child.layout(vt, styles, pod)?.into_frame(); + frame = child.layout(engine, styles, pod)?.into_frame(); // Enforce correct size. *frame.size_mut() = expand.select(region, frame.size()); @@ -484,7 +485,7 @@ fn layout( frame.set_size(Size::splat(frame.size().max_by_side())); let length = frame.size().max_by_side().min(region.min_by_side()); let pod = Regions::one(Size::splat(length), Axes::splat(true)); - frame = child.layout(vt, styles, pod)?.into_frame(); + frame = child.layout(engine, styles, pod)?.into_frame(); } // Enforce correct size again. |
