Rework Vt
into Engine
- Moves as much data out of the `Vm` - Removes duplication with call_vm and call_vt flavours - Uses tracked chain instead of fixed int for determining max nesting depth - This means that nesting checks now generalizes to layout and realization, to detect crashing show rules and overly nested layouts
This commit is contained in:
parent
2f795b5c07
commit
85b1d1d4dd
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
159
crates/typst/src/engine.rs
Normal file
159
crates/typst/src/engine.rs
Normal file
@ -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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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 scopes = Scopes::new(Some(world.library()));
|
||||
let mut vm = Vm::new(vt, route.track(), Some(id), scopes);
|
||||
|
||||
let root = source.root();
|
||||
let scopes = Scopes::new(Some(world.library()));
|
||||
let mut vm = Vm::new(engine, scopes, root.span());
|
||||
|
||||
// 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.
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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")?)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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])))
|
||||
}
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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)?
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}');
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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)))
|
||||
})
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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())?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
@ -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()
|
||||
|
@ -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())?;
|
||||
|
@ -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> {
|
||||
|
@ -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> {
|
||||
|
@ -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() {
|
||||
|
@ -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> {
|
||||
|
@ -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.
|
||||
|
BIN
tests/ref/compute/eval-path.png
Normal file
BIN
tests/ref/compute/eval-path.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -57,7 +57,7 @@ fn bench_edit(iai: &mut Iai) {
|
||||
|
||||
fn bench_eval(iai: &mut Iai) {
|
||||
let world = BenchWorld::new();
|
||||
let route = typst::eval::Route::default();
|
||||
let route = typst::engine::Route::default();
|
||||
let mut tracer = typst::eval::Tracer::new();
|
||||
iai.run(|| {
|
||||
typst::eval::eval(world.track(), route.track(), tracer.track_mut(), &world.source)
|
||||
|
@ -535,7 +535,7 @@ fn test_part(
|
||||
|
||||
if world.print.model {
|
||||
let world = (world as &dyn World).track();
|
||||
let route = typst::eval::Route::default();
|
||||
let route = typst::engine::Route::default();
|
||||
let mut tracer = typst::eval::Tracer::new();
|
||||
|
||||
let module =
|
||||
|
@ -31,12 +31,41 @@
|
||||
#let f = () => f
|
||||
#test(type(f()), int)
|
||||
|
||||
---
|
||||
// Test redefinition.
|
||||
#let f(x) = "hello"
|
||||
#let f(x) = if x != none { f(none) } else { "world" }
|
||||
#test(f(1), "world")
|
||||
|
||||
---
|
||||
// Error: 15-21 maximum function call depth exceeded
|
||||
#let rec(n) = rec(n) + 1
|
||||
#rec(1)
|
||||
|
||||
---
|
||||
#let f(x) = "hello"
|
||||
#let f(x) = if x != none { f(none) } else { "world" }
|
||||
#test(f(1), "world")
|
||||
// Test cyclic imports during layout.
|
||||
// Error: 2-38 maximum layout depth exceeded
|
||||
// Hint: 2-38 try to reduce the amount of nesting in your layout
|
||||
#layout(_ => include "recursion.typ")
|
||||
|
||||
---
|
||||
// Test recursive show rules.
|
||||
// Error: 22-25 maximum show rule depth exceeded
|
||||
// Hint: 22-25 check whether the show rule matches its own output
|
||||
// Hint: 22-25 this is a current compiler limitation that will be resolved in the future
|
||||
#show math.equation: $x$
|
||||
$ x $
|
||||
|
||||
---
|
||||
// Error: 18-21 maximum show rule depth exceeded
|
||||
// Hint: 18-21 check whether the show rule matches its own output
|
||||
// Hint: 18-21 this is a current compiler limitation that will be resolved in the future
|
||||
#show "hey": box[hey]
|
||||
hey
|
||||
|
||||
---
|
||||
// Error: 14-19 maximum show rule depth exceeded
|
||||
// Hint: 14-19 check whether the show rule matches its own output
|
||||
// Hint: 14-19 this is a current compiler limitation that will be resolved in the future
|
||||
#show "hey": "hey"
|
||||
hey
|
||||
|
18
tests/typ/compute/eval-path.typ
Normal file
18
tests/typ/compute/eval-path.typ
Normal file
@ -0,0 +1,18 @@
|
||||
// Test file loading in eval.
|
||||
|
||||
---
|
||||
// Test absolute path.
|
||||
#eval("image(\"/files/tiger.jpg\", width: 50%)")
|
||||
|
||||
---
|
||||
#show raw: it => eval(it.text, mode: "markup")
|
||||
|
||||
```
|
||||
#show emph: image("/files/tiger.jpg", width: 50%)
|
||||
_Tiger!_
|
||||
```
|
||||
|
||||
---
|
||||
// Test relative path.
|
||||
// Ref: false
|
||||
#test(eval(`"HELLO" in read("./eval-path.typ")`.text), true)
|
@ -102,31 +102,6 @@ Blue #move(dy: -0.15em)[🌊]
|
||||
// Error: 7-17 cannot continue outside of loop
|
||||
#eval("continue")
|
||||
|
||||
---
|
||||
// Error: 7-32 cannot access file system from here
|
||||
#eval("include \"../coma.typ\"")
|
||||
|
||||
---
|
||||
// Error: 7-30 cannot access file system from here
|
||||
#eval("image(\"/tiger.jpg\")")
|
||||
|
||||
---
|
||||
// Error: 23-30 cannot access file system from here
|
||||
#show raw: it => eval(it.text)
|
||||
|
||||
```
|
||||
image("/tiger.jpg")
|
||||
```
|
||||
|
||||
---
|
||||
// Error: 23-42 cannot access file system from here
|
||||
#show raw: it => eval("[" + it.text + "]")
|
||||
|
||||
```
|
||||
#show emph: _ => image("/giraffe.jpg")
|
||||
_No relative giraffe!_
|
||||
```
|
||||
|
||||
---
|
||||
// Error: 7-12 expected semicolon or line break
|
||||
#eval("1 2")
|
||||
|
Loading…
x
Reference in New Issue
Block a user