summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-09-20 13:05:55 +0200
committerLaurenz <laurmaedje@gmail.com>2022-09-20 16:37:15 +0200
commit757a701c1aa2a6fb80033c7e75666661818da6f9 (patch)
tree0415fec94d3856f4ebc97a1744cf2ba75fe8e7aa /src
parente29f55bb294cc298daad97accf6d8a76976b409c (diff)
A New World
Diffstat (limited to 'src')
-rw-r--r--src/diag.rs10
-rw-r--r--src/eval/array.rs14
-rw-r--r--src/eval/capture.rs4
-rw-r--r--src/eval/dict.rs4
-rw-r--r--src/eval/func.rs21
-rw-r--r--src/eval/methods.rs4
-rw-r--r--src/eval/mod.rs153
-rw-r--r--src/eval/scope.rs4
-rw-r--r--src/eval/vm.rs (renamed from src/eval/machine.rs)26
-rw-r--r--src/export/pdf/image.rs70
-rw-r--r--src/export/render.rs4
-rw-r--r--src/font/book.rs4
-rw-r--r--src/font/mod.rs2
-rw-r--r--src/image.rs2
-rw-r--r--src/lib.rs110
-rw-r--r--src/library/graphics/hide.rs6
-rw-r--r--src/library/graphics/image.rs7
-rw-r--r--src/library/graphics/line.rs4
-rw-r--r--src/library/graphics/shape.rs8
-rw-r--r--src/library/graphics/transform.rs12
-rw-r--r--src/library/layout/align.rs6
-rw-r--r--src/library/layout/columns.rs10
-rw-r--r--src/library/layout/container.rs4
-rw-r--r--src/library/layout/flow.rs10
-rw-r--r--src/library/layout/grid.rs20
-rw-r--r--src/library/layout/pad.rs6
-rw-r--r--src/library/layout/page.rs16
-rw-r--r--src/library/layout/place.rs6
-rw-r--r--src/library/layout/spacing.rs4
-rw-r--r--src/library/layout/stack.rs10
-rw-r--r--src/library/math/mod.rs6
-rw-r--r--src/library/math/rex.rs7
-rw-r--r--src/library/prelude.rs7
-rw-r--r--src/library/structure/doc.rs4
-rw-r--r--src/library/structure/heading.rs12
-rw-r--r--src/library/structure/list.rs12
-rw-r--r--src/library/structure/reference.rs4
-rw-r--r--src/library/structure/table.rs12
-rw-r--r--src/library/text/deco.rs4
-rw-r--r--src/library/text/link.rs6
-rw-r--r--src/library/text/mod.rs16
-rw-r--r--src/library/text/par.rs66
-rw-r--r--src/library/text/raw.rs6
-rw-r--r--src/library/text/repeat.rs6
-rw-r--r--src/library/text/shaping.rs32
-rw-r--r--src/library/text/shift.rs14
-rw-r--r--src/library/utility/color.rs6
-rw-r--r--src/library/utility/data.rs4
-rw-r--r--src/library/utility/math.rs18
-rw-r--r--src/library/utility/mod.rs19
-rw-r--r--src/library/utility/string.rs14
-rw-r--r--src/loading.rs239
-rw-r--r--src/main.rs301
-rw-r--r--src/model/content.rs30
-rw-r--r--src/model/layout.rs22
-rw-r--r--src/model/recipe.rs12
-rw-r--r--src/model/show.rs14
-rw-r--r--src/model/styles.rs12
-rw-r--r--src/parse/incremental.rs22
-rw-r--r--src/parse/mod.rs24
-rw-r--r--src/parse/parser.rs8
-rw-r--r--src/parse/resolve.rs4
-rw-r--r--src/parse/tokens.rs24
-rw-r--r--src/source.rs278
-rw-r--r--src/syntax/highlight.rs6
-rw-r--r--src/syntax/mod.rs4
-rw-r--r--src/syntax/span.rs4
-rw-r--r--src/util/buffer.rs59
-rw-r--r--src/util/mod.rs2
69 files changed, 854 insertions, 1047 deletions
diff --git a/src/diag.rs b/src/diag.rs
index c4438307..e96dfb00 100644
--- a/src/diag.rs
+++ b/src/diag.rs
@@ -5,7 +5,7 @@ use std::io;
use std::path::Path;
use crate::syntax::{Span, Spanned};
-use crate::Context;
+use crate::World;
/// Early-return with a [`TypError`].
#[macro_export]
@@ -101,21 +101,21 @@ where
/// Enrich a [`TypResult`] with a tracepoint.
pub trait Trace<T> {
/// Add the tracepoint to all errors that lie outside the `span`.
- fn trace<F>(self, ctx: &Context, make_point: F, span: Span) -> Self
+ fn trace<F>(self, world: &dyn World, make_point: F, span: Span) -> Self
where
F: Fn() -> Tracepoint;
}
impl<T> Trace<T> for TypResult<T> {
- fn trace<F>(self, ctx: &Context, make_point: F, span: Span) -> Self
+ fn trace<F>(self, world: &dyn World, make_point: F, span: Span) -> Self
where
F: Fn() -> Tracepoint,
{
self.map_err(|mut errors| {
- let range = ctx.sources.range(span);
+ let range = world.source(span.source()).range(span);
for error in errors.iter_mut() {
// Skip traces that surround the error.
- let error_range = ctx.sources.range(error.span);
+ let error_range = world.source(error.span.source()).range(error.span);
if range.start <= error_range.start && range.end >= error_range.end {
continue;
}
diff --git a/src/eval/array.rs b/src/eval/array.rs
index 43261a22..6d558393 100644
--- a/src/eval/array.rs
+++ b/src/eval/array.rs
@@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter, Write};
use std::ops::{Add, AddAssign};
use std::sync::Arc;
-use super::{ops, Args, Func, Machine, Value};
+use super::{ops, Args, Func, Value, Vm};
use crate::diag::{At, StrResult, TypResult};
use crate::syntax::Spanned;
use crate::util::ArcExt;
@@ -124,7 +124,7 @@ impl Array {
}
/// Return the first matching element.
- pub fn find(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Option<Value>> {
+ pub fn find(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<Option<Value>> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@@ -136,7 +136,7 @@ impl Array {
}
/// Return the index of the first matching element.
- pub fn position(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Option<i64>> {
+ pub fn position(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<Option<i64>> {
for (i, item) in self.iter().enumerate() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@@ -149,7 +149,7 @@ impl Array {
/// Return a new array with only those elements for which the function
/// returns true.
- pub fn filter(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Self> {
+ pub fn filter(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<Self> {
let mut kept = vec![];
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
@@ -161,7 +161,7 @@ impl Array {
}
/// Transform each item in the array with a function.
- pub fn map(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Self> {
+ pub fn map(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<Self> {
let enumerate = f.v.argc() == Some(2);
Ok(self
.iter()
@@ -178,7 +178,7 @@ impl Array {
}
/// Whether any element matches.
- pub fn any(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<bool> {
+ pub fn any(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<bool> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@@ -190,7 +190,7 @@ impl Array {
}
/// Whether all elements match.
- pub fn all(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<bool> {
+ pub fn all(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<bool> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if !f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
diff --git a/src/eval/capture.rs b/src/eval/capture.rs
index bbda96ad..b7570fe9 100644
--- a/src/eval/capture.rs
+++ b/src/eval/capture.rs
@@ -136,14 +136,14 @@ mod tests {
use crate::parse::parse;
#[track_caller]
- fn test(src: &str, result: &[&str]) {
+ fn test(text: &str, result: &[&str]) {
let mut scopes = Scopes::new(None);
scopes.top.define("x", 0);
scopes.top.define("y", 0);
scopes.top.define("z", 0);
let mut visitor = CapturesVisitor::new(&scopes);
- let root = parse(src);
+ let root = parse(text);
visitor.visit(&root);
let captures = visitor.finish();
diff --git a/src/eval/dict.rs b/src/eval/dict.rs
index 837933b1..3ba72c8a 100644
--- a/src/eval/dict.rs
+++ b/src/eval/dict.rs
@@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter, Write};
use std::ops::{Add, AddAssign};
use std::sync::Arc;
-use super::{Args, Array, Func, Machine, Str, Value};
+use super::{Args, Array, Func, Str, Value, Vm};
use crate::diag::{StrResult, TypResult};
use crate::parse::is_ident;
use crate::syntax::Spanned;
@@ -101,7 +101,7 @@ impl Dict {
}
/// Transform each pair in the array with a function.
- pub fn map(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Array> {
+ pub fn map(&self, vm: &mut Vm, f: Spanned<Func>) -> TypResult<Array> {
Ok(self
.iter()
.map(|(key, value)| {
diff --git a/src/eval/func.rs b/src/eval/func.rs
index bd312d66..d6b5252a 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -2,13 +2,13 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
-use super::{Args, Eval, Flow, Machine, Scope, Scopes, Value};
+use super::{Args, Eval, Flow, Scope, Scopes, Value, Vm};
use crate::diag::{StrResult, TypResult};
use crate::model::{Content, NodeId, StyleMap};
use crate::source::SourceId;
use crate::syntax::ast::Expr;
use crate::util::EcoString;
-use crate::Context;
+use crate::World;
/// An evaluatable function.
#[derive(Clone, Hash)]
@@ -29,7 +29,7 @@ impl Func {
/// Create a new function from a native rust function.
pub fn from_fn(
name: &'static str,
- func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
+ func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
) -> Self {
Self(Arc::new(Repr::Native(Native {
name,
@@ -86,7 +86,7 @@ impl Func {
}
/// Call the function with the given arguments.
- pub fn call(&self, vm: &mut Machine, mut args: Args) -> TypResult<Value> {
+ pub fn call(&self, vm: &mut Vm, mut args: Args) -> TypResult<Value> {
let value = match self.0.as_ref() {
Repr::Native(native) => (native.func)(vm, &mut args)?,
Repr::Closure(closure) => closure.call(vm, &mut args)?,
@@ -100,8 +100,8 @@ impl Func {
}
/// Call the function without an existing virtual machine.
- pub fn call_detached(&self, ctx: &mut Context, args: Args) -> TypResult<Value> {
- let mut vm = Machine::new(ctx, vec![], Scopes::new(None));
+ pub fn call_detached(&self, world: &dyn World, args: Args) -> TypResult<Value> {
+ let mut vm = Vm::new(world, vec![], Scopes::new(None));
self.call(&mut vm, args)
}
@@ -144,7 +144,7 @@ struct Native {
/// The name of the function.
pub name: &'static str,
/// The function pointer.
- pub func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
+ pub func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
/// The set rule.
pub set: Option<fn(&mut Args) -> TypResult<StyleMap>>,
/// The id of the node to customize with this function's show rule.
@@ -169,7 +169,7 @@ pub trait Node: 'static {
///
/// This is passed only the arguments that remain after execution of the
/// node's set rule.
- fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content>;
+ fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Content>;
/// Parse relevant arguments into style properties for this node.
///
@@ -198,7 +198,7 @@ pub struct Closure {
impl Closure {
/// Call the function in the context with the arguments.
- pub fn call(&self, vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
+ pub fn call(&self, vm: &mut Vm, args: &mut Args) -> TypResult<Value> {
// Don't leak the scopes from the call site. Instead, we use the scope
// of captured variables we collected earlier.
let mut scopes = Scopes::new(None);
@@ -228,9 +228,8 @@ impl Closure {
};
// Evaluate the body.
- let mut sub = Machine::new(vm.ctx, route, scopes);
+ let mut sub = Vm::new(vm.world, route, scopes);
let result = self.body.eval(&mut sub);
- vm.deps.extend(sub.deps);
// Handle control flow.
match sub.flow {
diff --git a/src/eval/methods.rs b/src/eval/methods.rs
index 5072e688..08d7dd3f 100644
--- a/src/eval/methods.rs
+++ b/src/eval/methods.rs
@@ -1,13 +1,13 @@
//! Methods on values.
-use super::{Args, Machine, Value};
+use super::{Args, Value, Vm};
use crate::diag::{At, TypResult};
use crate::syntax::Span;
use crate::util::EcoString;
/// Call a method on a value.
pub fn call(
- vm: &mut Machine,
+ vm: &mut Vm,
value: Value,
method: &str,
mut args: Args,
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 2ab94785..bae9ac94 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -13,11 +13,11 @@ mod value;
mod args;
mod capture;
mod func;
-mod machine;
pub mod methods;
pub mod ops;
mod raw;
mod scope;
+mod vm;
pub use self::str::*;
pub use args::*;
@@ -26,25 +26,25 @@ pub use capture::*;
pub use cast::*;
pub use dict::*;
pub use func::*;
-pub use machine::*;
pub use raw::*;
pub use scope::*;
pub use typst_macros::node;
pub use value::*;
+pub use vm::*;
use std::collections::BTreeMap;
use unicode_segmentation::UnicodeSegmentation;
-use crate::diag::{At, StrResult, Trace, Tracepoint, TypResult};
+use crate::diag::{failed_to_load, At, StrResult, Trace, Tracepoint, TypResult};
use crate::geom::{Angle, Em, Fraction, Length, Ratio};
use crate::library;
use crate::model::{Content, Pattern, Recipe, StyleEntry, StyleMap};
-use crate::source::{SourceId, SourceStore};
+use crate::source::SourceId;
use crate::syntax::ast::*;
use crate::syntax::{Span, Spanned};
use crate::util::EcoString;
-use crate::Context;
+use crate::World;
/// Evaluate a source file and return the resulting module.
///
@@ -52,29 +52,24 @@ use crate::Context;
/// layoutable contents or diagnostics in the form of a vector of error
/// messages with file and span information.
pub fn evaluate(
- ctx: &mut Context,
+ world: &dyn World,
id: SourceId,
mut route: Vec<SourceId>,
) -> TypResult<Module> {
// Prevent cyclic evaluation.
if route.contains(&id) {
- let path = ctx.sources.get(id).path().display();
+ let path = world.source(id).path().display();
panic!("Tried to cyclicly evaluate {}", path);
}
route.push(id);
- // Parse the file.
- let source = ctx.sources.get(id);
- let ast = source.ast()?;
- let rev = source.rev();
-
// Evaluate the module.
- let std = ctx.config.std.clone();
- let scopes = Scopes::new(Some(&std));
- let mut vm = Machine::new(ctx, route, scopes);
+ let ast = world.source(id).ast()?;
+ let std = &world.config().std;
+ let scopes = Scopes::new(Some(std));
+ let mut vm = Vm::new(world, route, scopes);
let result = ast.eval(&mut vm);
- vm.deps.push((id, rev));
// Handle control flow.
if let Some(flow) = vm.flow {
@@ -82,11 +77,7 @@ pub fn evaluate(
}
// Assemble the module.
- Ok(Module {
- scope: vm.scopes.top,
- content: result?,
- deps: vm.deps,
- })
+ Ok(Module { scope: vm.scopes.top, content: result? })
}
/// An evaluated module, ready for importing or layouting.
@@ -96,15 +87,6 @@ pub struct Module {
pub scope: Scope,
/// The module's layoutable contents.
pub content: Content,
- /// The source file revisions this module depends on.
- pub deps: Vec<(SourceId, usize)>,
-}
-
-impl Module {
- /// Whether the module is still valid for the given sources.
- pub fn valid(&self, sources: &SourceStore) -> bool {
- self.deps.iter().all(|&(id, rev)| rev == sources.get(id).rev())
- }
}
/// Evaluate an expression.
@@ -113,20 +95,20 @@ pub trait Eval {
type Output;
/// Evaluate the expression to the output value.
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output>;
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output>;
}
impl Eval for Markup {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
eval_markup(vm, &mut self.nodes())
}
}
/// Evaluate a stream of markup nodes.
fn eval_markup(
- vm: &mut Machine,
+ vm: &mut Vm,
nodes: &mut impl Iterator<Item = MarkupNode>,
) -> TypResult<Content> {
let flow = vm.flow.take();
@@ -175,7 +157,7 @@ fn eval_markup(
impl Eval for MarkupNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(match self {
Self::Space => Content::Space,
Self::Parbreak => Content::Parbreak,
@@ -199,7 +181,7 @@ impl Eval for MarkupNode {
impl Eval for StrongNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::show(library::text::StrongNode(
self.body().eval(vm)?,
)))
@@ -209,7 +191,7 @@ impl Eval for StrongNode {
impl Eval for EmphNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::show(library::text::EmphNode(
self.body().eval(vm)?,
)))
@@ -219,7 +201,7 @@ impl Eval for EmphNode {
impl Eval for RawNode {
type Output = Content;
- fn eval(&self, _: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
let content = Content::show(library::text::RawNode {
text: self.text.clone(),
block: self.block,
@@ -234,7 +216,7 @@ impl Eval for RawNode {
impl Eval for Spanned<MathNode> {
type Output = Content;
- fn eval(&self, _: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::show(library::math::MathNode {
formula: self.clone().map(|math| math.formula),
display: self.v.display,
@@ -245,7 +227,7 @@ impl Eval for Spanned<MathNode> {
impl Eval for HeadingNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::show(library::structure::HeadingNode {
body: self.body().eval(vm)?,
level: self.level(),
@@ -256,7 +238,7 @@ impl Eval for HeadingNode {
impl Eval for ListNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::Item(library::structure::ListItem {
kind: library::structure::UNORDERED,
number: None,
@@ -268,7 +250,7 @@ impl Eval for ListNode {
impl Eval for EnumNode {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
Ok(Content::Item(library::structure::ListItem {
kind: library::structure::ORDERED,
number: self.number(),
@@ -280,7 +262,7 @@ impl Eval for EnumNode {
impl Eval for Expr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let forbidden = |name| {
error!(
self.span(),
@@ -321,7 +303,7 @@ impl Eval for Expr {
impl Eval for Lit {
type Output = Value;
- fn eval(&self, _: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
Ok(match self.kind() {
LitKind::None => Value::None,
LitKind::Auto => Value::Auto,
@@ -343,7 +325,7 @@ impl Eval for Lit {
impl Eval for Ident {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
vm.scopes.get(self).cloned().at(self.span())
}
}
@@ -351,7 +333,7 @@ impl Eval for Ident {
impl Eval for CodeBlock {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
vm.scopes.enter();
let output = eval_code(vm, &mut self.exprs())?;
vm.scopes.exit();
@@ -360,10 +342,7 @@ impl Eval for CodeBlock {
}
/// Evaluate a stream of expressions.
-fn eval_code(
- vm: &mut Machine,
- exprs: &mut impl Iterator<Item = Expr>,
-) -> TypResult<Value> {
+fn eval_code(vm: &mut Vm, exprs: &mut impl Iterator<Item = Expr>) -> TypResult<Value> {
let flow = vm.flow.take();
let mut output = Value::None;
@@ -415,7 +394,7 @@ fn eval_code(
impl Eval for ContentBlock {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
vm.scopes.enter();
let content = self.body().eval(vm)?;
vm.scopes.exit();
@@ -426,7 +405,7 @@ impl Eval for ContentBlock {
impl Eval for GroupExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
self.expr().eval(vm)
}
}
@@ -434,7 +413,7 @@ impl Eval for GroupExpr {
impl Eval for ArrayExpr {
type Output = Array;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let items = self.items();
let mut vec = Vec::with_capacity(items.size_hint().0);
@@ -456,7 +435,7 @@ impl Eval for ArrayExpr {
impl Eval for DictExpr {
type Output = Dict;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let mut map = BTreeMap::new();
for item in self.items() {
@@ -486,7 +465,7 @@ impl Eval for DictExpr {
impl Eval for UnaryExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let value = self.expr().eval(vm)?;
let result = match self.op() {
UnOp::Pos => ops::pos(value),
@@ -500,7 +479,7 @@ impl Eval for UnaryExpr {
impl Eval for BinaryExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
match self.op() {
BinOp::Add => self.apply(vm, ops::add),
BinOp::Sub => self.apply(vm, ops::sub),
@@ -529,7 +508,7 @@ impl BinaryExpr {
/// Apply a basic binary operation.
fn apply(
&self,
- vm: &mut Machine,
+ vm: &mut Vm,
op: fn(Value, Value) -> StrResult<Value>,
) -> TypResult<Value> {
let lhs = self.lhs().eval(vm)?;
@@ -548,7 +527,7 @@ impl BinaryExpr {
/// Apply an assignment operation.
fn assign(
&self,
- vm: &mut Machine,
+ vm: &mut Vm,
op: fn(Value, Value) -> StrResult<Value>,
) -> TypResult<Value> {
let rhs = self.rhs().eval(vm)?;
@@ -562,7 +541,7 @@ impl BinaryExpr {
impl Eval for FieldAccess {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let object = self.object().eval(vm)?;
let span = self.field().span();
let field = self.field().take();
@@ -588,7 +567,7 @@ impl Eval for FieldAccess {
impl Eval for FuncCall {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let callee = self.callee().eval(vm)?;
let args = self.args().eval(vm)?;
@@ -597,7 +576,7 @@ impl Eval for FuncCall {
Value::Dict(dict) => dict.get(&args.into_key()?).at(self.span())?.clone(),
Value::Func(func) => {
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
- func.call(vm, args).trace(vm.ctx, point, self.span())?
+ func.call(vm, args).trace(vm.world, point, self.span())?
}
v => bail!(
@@ -612,7 +591,7 @@ impl Eval for FuncCall {
impl Eval for MethodCall {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let span = self.span();
let method = self.method();
let point = || Tracepoint::Call(Some(method.to_string()));
@@ -621,12 +600,12 @@ impl Eval for MethodCall {
let args = self.args().eval(vm)?;
let mut value = self.receiver().access(vm)?;
methods::call_mut(&mut value, &method, args, span)
- .trace(vm.ctx, point, span)?;
+ .trace(vm.world, point, span)?;
Value::None
} else {
let value = self.receiver().eval(vm)?;
let args = self.args().eval(vm)?;
- methods::call(vm, value, &method, args, span).trace(vm.ctx, point, span)?
+ methods::call(vm, value, &method, args, span).trace(vm.world, point, span)?
})
}
}
@@ -634,7 +613,7 @@ impl Eval for MethodCall {
impl Eval for CallArgs {
type Output = Args;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let mut items = Vec::new();
for arg in self.items() {
@@ -683,7 +662,7 @@ impl Eval for CallArgs {
impl Eval for ClosureExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
// The closure's name is defined by its let binding if there's one.
let name = self.name().map(Ident::take);
@@ -730,7 +709,7 @@ impl Eval for ClosureExpr {
impl Eval for LetExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let value = match self.init() {
Some(expr) => expr.eval(vm)?,
None => Value::None,
@@ -743,7 +722,7 @@ impl Eval for LetExpr {
impl Eval for SetExpr {
type Output = StyleMap;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let target = self.target();
let target = target.eval(vm)?.cast::<Func>().at(target.span())?;
let args = self.args().eval(vm)?;
@@ -754,7 +733,7 @@ impl Eval for SetExpr {
impl Eval for ShowExpr {
type Output = Recipe;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
// Evaluate the target function.
let pattern = self.pattern();
let pattern = pattern.eval(vm)?.cast::<Pattern>().at(pattern.span())?;
@@ -791,7 +770,7 @@ impl Eval for ShowExpr {
impl Eval for IfExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let condition = self.condition();
if condition.eval(vm)?.cast::<bool>().at(condition.span())? {
self.if_body().eval(vm)
@@ -806,7 +785,7 @@ impl Eval for IfExpr {
impl Eval for WhileExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let flow = vm.flow.take();
let mut output = Value::None;
@@ -838,7 +817,7 @@ impl Eval for WhileExpr {
impl Eval for ForExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let flow = vm.flow.take();
let mut output = Value::None;
vm.scopes.enter();
@@ -917,7 +896,7 @@ impl Eval for ForExpr {
impl Eval for ImportExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let span = self.path().span();
let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
let module = import(vm, &path, span)?;
@@ -946,7 +925,7 @@ impl Eval for ImportExpr {
impl Eval for IncludeExpr {
type Output = Content;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let span = self.path().span();
let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
let module = import(vm, &path, span)?;
@@ -955,10 +934,14 @@ impl Eval for IncludeExpr {
}
/// Process an import of a module relative to the current location.
-fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult<Module> {
+fn import(vm: &mut Vm, path: &str, span: Span) -> TypResult<Module> {
// Load the source file.
let full = vm.locate(&path).at(span)?;
- let id = vm.ctx.sources.load(&full).at(span)?;
+ let id = vm
+ .world
+ .resolve(&full)
+ .map_err(|err| failed_to_load("source file", &full, err))
+ .at(span)?;
// Prevent cyclic importing.
if vm.route.contains(&id) {
@@ -968,9 +951,7 @@ fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult<Module> {
// Evaluate the file.
let route = vm.route.clone();
let module =
- evaluate(vm.ctx, id, route).trace(vm.ctx, || Tracepoint::Import, span)?;
-
- vm.deps.extend(module.deps.iter().cloned());
+ evaluate(vm.world, id, route).trace(vm.world, || Tracepoint::Import, span)?;
Ok(module)
}
@@ -978,7 +959,7 @@ fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult<Module> {
impl Eval for BreakExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
if vm.flow.is_none() {
vm.flow = Some(Flow::Break(self.span()));
}
@@ -989,7 +970,7 @@ impl Eval for BreakExpr {
impl Eval for ContinueExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
if vm.flow.is_none() {
vm.flow = Some(Flow::Continue(self.span()));
}
@@ -1000,7 +981,7 @@ impl Eval for ContinueExpr {
impl Eval for ReturnExpr {
type Output = Value;
- fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
+ fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
let value = self.body().map(|body| body.eval(vm)).transpose()?;
if vm.flow.is_none() {
vm.flow = Some(Flow::Return(self.span(), value));
@@ -1012,11 +993,11 @@ impl Eval for ReturnExpr {
/// Access an expression mutably.
pub trait Access {
/// Access the value.
- fn access<'a>(&self, vm: &'a mut Machine) -> TypResult<&'a mut Value>;
+ fn access<'a>(&self, vm: &'a mut Vm) -> TypResult<&'a mut Value>;
}
impl Access for Expr {
- fn access<'a>(&self, vm: &'a mut Machine) -> TypResult<&'a mut Value> {
+ fn access<'a>(&self, vm: &'a mut Vm) -> TypResult<&'a mut Value> {
match self {
Expr::Ident(v) => v.access(vm),
Expr::FieldAccess(v) => v.access(vm),
@@ -1027,13 +1008,13 @@ impl Access for Expr {
}
impl Access for Ident {
- fn access<'a>(&self, vm: &'a mut Machine) -> TypResult<&'a mut Value> {
+ fn access<'a>(&self, vm: &'a mut Vm) -> TypResult<&'a mut Value> {
vm.scopes.get_mut(self).at(self.span())
}
}
impl Access for FieldAccess {
- fn access<'a>(&self, vm: &'a mut Machine) -> TypResult<&'a mut Value> {
+ fn access<'a>(&self, vm: &'a mut Vm) -> TypResult<&'a mut Value> {
Ok(match self.object().access(vm)? {
Value::Dict(dict) => dict.get_mut(self.field().take().into()),
v => bail!(
@@ -1046,7 +1027,7 @@ impl Access for FieldAccess {
}
impl Access for FuncCall {
- fn access<'a>(&self, vm: &'a mut Machine) -> TypResult<&'a mut Value> {
+ fn access<'a>(&self, vm: &'a mut Vm) -> TypResult<&'a mut Value> {
let args = self.args().eval(vm)?;
Ok(match self.callee().access(vm)? {
Value::Array(array) => array.get_mut(args.into_index()?).at(self.span())?,
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 7c624de0..1b11e6ea 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
-use super::{Args, Func, Machine, Node, Value};
+use super::{Args, Func, Node, Value, Vm};
use crate::diag::{StrResult, TypResult};
use crate::util::EcoString;
@@ -78,7 +78,7 @@ impl Scope {
pub fn def_fn(
&mut self,
name: &'static str,
- func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
+ func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
) {
self.define(name, Func::from_fn(name, func));
}
diff --git a/src/eval/machine.rs b/src/eval/vm.rs
index 9c58c659..937152cf 100644
--- a/src/eval/machine.rs
+++ b/src/eval/vm.rs
@@ -5,32 +5,24 @@ use crate::diag::{StrResult, TypError};
use crate::source::SourceId;
use crate::syntax::Span;
use crate::util::PathExt;
-use crate::Context;
+use crate::World;
/// A virtual machine.
-pub struct Machine<'a> {
+pub struct Vm<'w> {
/// The core context.
- pub ctx: &'a mut Context,
+ pub world: &'w dyn World,
/// The route of source ids the machine took to reach its current location.
pub route: Vec<SourceId>,
- /// The dependencies of the current evaluation process.
- pub deps: Vec<(SourceId, usize)>,
/// The stack of scopes.
- pub scopes: Scopes<'a>,
+ pub scopes: Scopes<'w>,
/// A control flow event that is currently happening.
pub flow: Option<Flow>,
}
-impl<'a> Machine<'a> {
+impl<'w> Vm<'w> {
/// Create a new virtual machine.
- pub fn new(ctx: &'a mut Context, route: Vec<SourceId>, scopes: Scopes<'a>) -> Self {
- Self {
- ctx,
- route,
- deps: vec![],
- scopes,
- flow: None,
- }
+ pub fn new(ctx: &'w dyn World, route: Vec<SourceId>, scopes: Scopes<'w>) -> Self {
+ Self { world: ctx, route, scopes, flow: None }
}
/// Resolve a user-entered path to be relative to the compilation
@@ -38,10 +30,10 @@ impl<'a> Machine<'a> {
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {
if let Some(&id) = self.route.last() {
if let Some(path) = path.strip_prefix('/') {
- return Ok(self.ctx.config.root.join(path).normalize());
+ return Ok(self.world.config().root.join(path).normalize());
}
- if let Some(dir) = self.ctx.sources.get(id).path().parent() {
+ if let Some(dir) = self.world.source(id).path().parent() {
return Ok(dir.join(path).normalize());
}
}
diff --git a/src/export/pdf/image.rs b/src/export/pdf/image.rs
index 7886524c..f148bb7d 100644
--- a/src/export/pdf/image.rs
+++ b/src/export/pdf/image.rs
@@ -16,48 +16,40 @@ pub fn write_images(ctx: &mut PdfContext) {
let height = image.height();
// Add the primary image.
+ // TODO: Error if image could not be encoded.
match image.decode().unwrap() {
DecodedImage::Raster(dynamic) => {
- if let Ok((data, filter, has_color)) =
- encode_image(image.format(), &dynamic)
- {
- let mut image = ctx.writer.image_xobject(image_ref, &data);
- image.filter(filter);
- image.width(width as i32);
- image.height(height as i32);
- image.bits_per_component(8);
-
- let space = image.color_space();
- if has_color {
- space.device_rgb();
- } else {
- space.device_gray();
- }
-
- // Add a second gray-scale image containing the alpha values if
- // this image has an alpha channel.
- if dynamic.color().has_alpha() {
- let (alpha_data, alpha_filter) = encode_alpha(&dynamic);
- let mask_ref = ctx.alloc.bump();
- image.s_mask(mask_ref);
- image.finish();
-
- let mut mask = ctx.writer.image_xobject(mask_ref, &alpha_data);
- mask.filter(alpha_filter);
- mask.width(width as i32);
- mask.height(height as i32);
- mask.color_space().device_gray();
- mask.bits_per_component(8);
- }
+ // TODO: Error if image could not be encoded.
+ let (data, filter, has_color) =
+ encode_image(image.format(), &dynamic).unwrap();
+
+ let mut image = ctx.writer.image_xobject(image_ref, &data);
+ image.filter(filter);
+ image.width(width as i32);
+ image.height(height as i32);
+ image.bits_per_component(8);
+
+ let space = image.color_space();
+ if has_color {
+ space.device_rgb();
} else {
- // TODO: Warn that image could not be encoded.
- ctx.writer
- .image_xobject(image_ref, &[])
- .width(0)
- .height(0)
- .bits_per_component(1)
- .color_space()
- .device_gray();
+ space.device_gray();
+ }
+
+ // Add a second gray-scale image containing the alpha values if
+ // this image has an alpha channel.
+ if dynamic.color().has_alpha() {
+ let (alpha_data, alpha_filter) = encode_alpha(&dynamic);
+ let mask_ref = ctx.alloc.bump();
+ image.s_mask(mask_ref);
+ image.finish();
+
+ let mut mask = ctx.writer.image_xobject(mask_ref, &alpha_data);
+ mask.filter(alpha_filter);
+ mask.width(width as i32);
+ mask.height(height as i32);
+ mask.color_space().device_gray();
+ mask.bits_per_component(8);
}
}
DecodedImage::Svg(svg) => {
diff --git a/src/export/render.rs b/src/export/render.rs
index bf735ded..3fb57ad6 100644
--- a/src/export/render.rs
+++ b/src/export/render.rs
@@ -147,8 +147,8 @@ fn render_svg_glyph(
}
// Parse XML.
- let src = std::str::from_utf8(data).ok()?;
- let document = roxmltree::Document::parse(src).ok()?;
+ let xml = std::str::from_utf8(data).ok()?;
+ let document = roxmltree::Document::parse(xml).ok()?;
let root = document.root_element();
// Parse SVG.
diff --git a/src/font/book.rs b/src/font/book.rs
index 8f19faf7..323eb84f 100644
--- a/src/font/book.rs
+++ b/src/font/book.rs
@@ -39,8 +39,8 @@ impl FontBook {
self.infos.push(info);
}
- /// An ordered iterator over all font families this loader knows and details
- /// about the faces that are part of them.
+ /// An ordered iterator over all font families this book knows and details
+ /// about the fonts that are part of them.
pub fn families(
&self,
) -> impl Iterator<Item = (&str, impl Iterator<Item = &FontInfo>)> + '_ {
diff --git a/src/font/mod.rs b/src/font/mod.rs
index 917fea62..2404ad32 100644
--- a/src/font/mod.rs
+++ b/src/font/mod.rs
@@ -15,7 +15,7 @@ use rex::font::MathHeader;
use ttf_parser::{GlyphId, Tag};
use crate::geom::Em;
-use crate::loading::Buffer;
+use crate::util::Buffer;
/// An OpenType font.
#[derive(Clone)]
diff --git a/src/image.rs b/src/image.rs
index c2631477..db10a162 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -2,7 +2,7 @@
use std::io;
-use crate::loading::Buffer;
+use crate::util::Buffer;
/// A raster or vector image.
///
diff --git a/src/lib.rs b/src/lib.rs
index c26ef809..84d91d44 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -44,117 +44,75 @@ pub mod font;
pub mod frame;
pub mod image;
pub mod library;
-pub mod loading;
pub mod model;
pub mod parse;
pub mod source;
pub mod syntax;
-use std::path::PathBuf;
-use std::sync::Arc;
+use std::io;
+use std::path::{Path, PathBuf};
use crate::diag::TypResult;
use crate::eval::Scope;
+use crate::font::{Font, FontBook};
use crate::frame::Frame;
-use crate::loading::Loader;
use crate::model::StyleMap;
-use crate::source::{SourceId, SourceStore};
+use crate::source::{Source, SourceId};
+use crate::util::Buffer;
/// Typeset a source file into a collection of layouted frames.
///
/// Returns either a vector of frames representing individual pages or
/// diagnostics in the form of a vector of error message with file and span
/// information.
-pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult<Vec<Frame>> {
- let module = eval::evaluate(ctx, id, vec![])?;
- model::layout(ctx, &module.content)
+pub fn typeset(world: &dyn World, main: SourceId) -> TypResult<Vec<Frame>> {
+ let module = eval::evaluate(world, main, vec![])?;
+ model::layout(world, &module.content)
}
-/// The core context which holds the configuration and stores.
-pub struct Context {
- /// The loader for fonts and files.
- pub loader: Arc<dyn Loader>,
- /// Stores loaded source files.
- pub sources: SourceStore,
- /// The context's configuration.
- config: Config,
-}
+/// The environment in which typesetting occurs.
+pub trait World {
+ /// Access the global configuration.
+ fn config(&self) -> &Config;
-impl Context {
- /// Create a new context.
- pub fn new(loader: Arc<dyn Loader>, config: Config) -> Self {
- Self {
- loader: Arc::clone(&loader),
- sources: SourceStore::new(Arc::clone(&loader)),
- config,
- }
- }
-}
+ /// Resolve the unique id of a source file.
+ fn resolve(&self, path: &Path) -> io::Result<SourceId>;
-/// Compilation configuration.
-pub struct Config {
- /// The compilation root.
- pub root: PathBuf,
- /// The standard library scope.
- pub std: Arc<Scope>,
- /// The default styles.
- pub styles: Arc<StyleMap>,
-}
+ /// Access a source file by id.
+ fn source(&self, id: SourceId) -> &Source;
-impl Config {
- /// Create a new configuration builder.
- pub fn builder() -> ConfigBuilder {
- ConfigBuilder::default()
- }
-}
+ /// Metadata about all known fonts.
+ fn book(&self) -> &FontBook;
-impl Default for Config {
- fn default() -> Self {
- Self::builder().build()
- }
-}
+ /// Access the font with the given id.
+ fn font(&self, id: usize) -> io::Result<Font>;
-/// A builder for a [`Config`].
-///
-/// This struct is created by [`Config::builder`].
-#[derive(Debug, Default, Clone)]
-pub struct ConfigBuilder {
- root: PathBuf,
- std: Option<Arc<Scope>>,
- styles: Option<Arc<StyleMap>>,
+ /// Access a file at a path.
+ fn file(&self, path: &Path) -> io::Result<Buffer>;
}
-impl ConfigBuilder {
+/// The global configuration for typesetting.
+pub struct Config {
/// The compilation root, relative to which absolute paths are.
///
/// Default: Empty path.
- pub fn root(&mut self, root: impl Into<PathBuf>) -> &mut Self {
- self.root = root.into();
- self
- }
-
+ pub root: PathBuf,
/// The scope containing definitions that are available everywhere.
///
/// Default: Typst's standard library.
- pub fn std(&mut self, std: impl Into<Arc<Scope>>) -> &mut Self {
- self.std = Some(std.into());
- self
- }
-
+ pub std: Scope,
/// The default properties for page size, font selection and so on.
///
/// Default: Empty style map.
- pub fn styles(&mut self, styles: impl Into<Arc<StyleMap>>) -> &mut Self {
- self.styles = Some(styles.into());
- self
- }
+ pub styles: StyleMap,
+}
- /// Finish building the configuration.
- pub fn build(&self) -> Config {
- Config {
- root: self.root.clone(),
- std: self.std.clone().unwrap_or_else(|| Arc::new(library::new())),
- styles: self.styles.clone().unwrap_or_default(),
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ root: PathBuf::new(),
+ std: library::new(),
+ styles: StyleMap::new(),
}
}
}
diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs
index f40635a0..f2a423ce 100644
--- a/src/library/graphics/hide.rs
+++ b/src/library/graphics/hide.rs
@@ -6,7 +6,7 @@ pub struct HideNode(pub LayoutNode);
#[node]
impl HideNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}
@@ -14,11 +14,11 @@ impl HideNode {
impl Layout for HideNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
- let mut frames = self.0.layout(ctx, regions, styles)?;
+ let mut frames = self.0.layout(world, regions, styles)?;
for frame in &mut frames {
frame.clear();
}
diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs
index f8cdc4cd..1642c7b0 100644
--- a/src/library/graphics/image.rs
+++ b/src/library/graphics/image.rs
@@ -13,15 +13,14 @@ impl ImageNode {
/// How the image should adjust itself to a given area.
pub const FIT: ImageFit = ImageFit::Cover;
- fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Content> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to image file")?;
let full = vm.locate(&path).at(span)?;
let ext = full.extension().and_then(OsStr::to_str).unwrap_or_default();
let image = vm
- .ctx
- .loader
+ .world
.file(&full)
.and_then(|buffer| Image::new(buffer, ext))
.map_err(|err| failed_to_load("image", &full, err))
@@ -39,7 +38,7 @@ impl ImageNode {
impl Layout for ImageNode {
fn layout(
&self,
- _: &mut Context,
+ _: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs
index 15c54f46..95c3a709 100644
--- a/src/library/graphics/line.rs
+++ b/src/library/graphics/line.rs
@@ -15,7 +15,7 @@ impl LineNode {
#[property(resolve, fold)]
pub const STROKE: RawStroke = RawStroke::default();
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let origin = args.named("origin")?.unwrap_or_default();
let delta = match args.named::<Spec<Relative<RawLength>>>("to")? {
@@ -40,7 +40,7 @@ impl LineNode {
impl Layout for LineNode {
fn layout(
&self,
- _: &mut Context,
+ _: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs
index 5cc5a76d..ee5e43e8 100644
--- a/src/library/graphics/shape.rs
+++ b/src/library/graphics/shape.rs
@@ -39,7 +39,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
pub const RADIUS: Corners<Option<Relative<RawLength>>> =
Corners::splat(Relative::zero());
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let size = match S {
SQUARE => args.named::<RawLength>("size")?.map(Relative::from),
CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)),
@@ -78,7 +78,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
impl<const S: ShapeKind> Layout for ShapeNode<S> {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -93,7 +93,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
let child = child.clone().padded(inset.map(|side| side.map(RawLength::from)));
let mut pod = Regions::one(regions.first, regions.base, regions.expand);
- frames = child.layout(ctx, &pod, styles)?;
+ frames = child.layout(world, &pod, styles)?;
for frame in frames.iter_mut() {
frame.apply_role(Role::GenericBlock);
@@ -113,7 +113,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
pod.first = Size::splat(length);
pod.expand = Spec::splat(true);
- frames = child.layout(ctx, &pod, styles)?;
+ frames = child.layout(world, &pod, styles)?;
}
} else {
// The default size that a shape takes on if it has no child and
diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs
index 48cadb1b..0a4f5b5f 100644
--- a/src/library/graphics/transform.rs
+++ b/src/library/graphics/transform.rs
@@ -12,7 +12,7 @@ pub struct MoveNode {
#[node]
impl MoveNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
Ok(Content::inline(Self {
@@ -25,11 +25,11 @@ impl MoveNode {
impl Layout for MoveNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
- let mut frames = self.child.layout(ctx, regions, styles)?;
+ let mut frames = self.child.layout(world, regions, styles)?;
let delta = self.delta.resolve(styles);
for frame in &mut frames {
@@ -62,7 +62,7 @@ impl<const T: TransformKind> TransformNode<T> {
#[property(resolve)]
pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default();
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let transform = match T {
ROTATE => {
let angle = args.named_or_find("angle")?.unwrap_or_default();
@@ -86,12 +86,12 @@ impl<const T: TransformKind> TransformNode<T> {
impl<const T: TransformKind> Layout for TransformNode<T> {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
- let mut frames = self.child.layout(ctx, regions, styles)?;
+ let mut frames = self.child.layout(world, regions, styles)?;
for frame in &mut frames {
let Spec { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs
index e7a27c04..3b1a4aaf 100644
--- a/src/library/layout/align.rs
+++ b/src/library/layout/align.rs
@@ -12,7 +12,7 @@ pub struct AlignNode {
#[node]
impl AlignNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default();
let body: Content = args.expect("body")?;
Ok(match (body, aligns) {
@@ -28,7 +28,7 @@ impl AlignNode {
impl Layout for AlignNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -43,7 +43,7 @@ impl Layout for AlignNode {
}
// Layout the child.
- let mut frames = self.child.layout(ctx, &pod, passed.chain(&styles))?;
+ let mut frames = self.child.layout(world, &pod, passed.chain(&styles))?;
for (region, frame) in regions.iter().zip(&mut frames) {
// Align in the target size. The target size depends on whether we
// should expand.
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index efc435aa..bfbbfd8d 100644
--- a/src/library/layout/columns.rs
+++ b/src/library/layout/columns.rs
@@ -17,7 +17,7 @@ impl ColumnsNode {
#[property(resolve)]
pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into();
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::block(Self {
columns: args.expect("column count")?,
child: args.expect("body")?,
@@ -28,14 +28,14 @@ impl ColumnsNode {
impl Layout for ColumnsNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
// Separating the infinite space into infinite columns does not make
// much sense.
if !regions.first.x.is_finite() {
- return self.child.layout(ctx, regions, styles);
+ return self.child.layout(world, regions, styles);
}
// Determine the width of the gutter and each column.
@@ -57,7 +57,7 @@ impl Layout for ColumnsNode {
};
// Layout the children.
- let mut frames = self.child.layout(ctx, &pod, styles)?.into_iter();
+ let mut frames = self.child.layout(world, &pod, styles)?.into_iter();
let mut finished = vec![];
let dir = styles.get(TextNode::DIR);
@@ -106,7 +106,7 @@ pub struct ColbreakNode;
#[node]
impl ColbreakNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Colbreak { weak })
}
diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs
index df03ac91..66a43751 100644
--- a/src/library/layout/container.rs
+++ b/src/library/layout/container.rs
@@ -5,7 +5,7 @@ pub struct BoxNode;
#[node]
impl BoxNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let width = args.named("width")?;
let height = args.named("height")?;
let body: LayoutNode = args.eat()?.unwrap_or_default();
@@ -18,7 +18,7 @@ pub struct BlockNode;
#[node]
impl BlockNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::Block(args.eat()?.unwrap_or_default()))
}
}
diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs
index c6d2999e..841b80aa 100644
--- a/src/library/layout/flow.rs
+++ b/src/library/layout/flow.rs
@@ -25,7 +25,7 @@ pub enum FlowChild {
impl Layout for FlowNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -38,7 +38,7 @@ impl Layout for FlowNode {
layouter.layout_spacing(*kind, styles);
}
FlowChild::Node(ref node) => {
- layouter.layout_node(ctx, node, styles)?;
+ layouter.layout_node(world, node, styles)?;
}
FlowChild::Colbreak => {
layouter.finish_region();
@@ -149,7 +149,7 @@ impl FlowLayouter {
/// Layout a node.
pub fn layout_node(
&mut self,
- ctx: &mut Context,
+ world: &dyn World,
node: &LayoutNode,
styles: StyleChain,
) -> TypResult<()> {
@@ -162,7 +162,7 @@ impl FlowLayouter {
// aligned later.
if let Some(placed) = node.downcast::<PlaceNode>() {
if placed.out_of_flow() {
- let frame = node.layout(ctx, &self.regions, styles)?.remove(0);
+ let frame = node.layout(world, &self.regions, styles)?.remove(0);
self.items.push(FlowItem::Placed(frame));
return Ok(());
}
@@ -180,7 +180,7 @@ impl FlowLayouter {
.unwrap_or(Align::Top),
);
- let frames = node.layout(ctx, &self.regions, styles)?;
+ let frames = node.layout(world, &self.regions, styles)?;
let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role.
diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs
index 93dbf97e..3fde9c10 100644
--- a/src/library/layout/grid.rs
+++ b/src/library/layout/grid.rs
@@ -13,7 +13,7 @@ pub struct GridNode {
#[node]
impl GridNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
@@ -33,13 +33,13 @@ impl GridNode {
impl Layout for GridNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
// Prepare grid layout by unifying content and gutter tracks.
let layouter = GridLayouter::new(
- ctx,
+ world,
self.tracks.as_deref(),
self.gutter.as_deref(),
&self.cells,
@@ -93,7 +93,7 @@ castable! {
/// Performs grid layout.
pub struct GridLayouter<'a> {
/// The core context.
- ctx: &'a mut Context,
+ world: &'a dyn World,
/// The grid cells.
cells: &'a [LayoutNode],
/// The column tracks including gutter tracks.
@@ -133,7 +133,7 @@ impl<'a> GridLayouter<'a> {
///
/// This prepares grid layout by unifying content and gutter tracks.
pub fn new(
- ctx: &'a mut Context,
+ world: &'a dyn World,
tracks: Spec<&[TrackSizing]>,
gutter: Spec<&[TrackSizing]>,
cells: &'a [LayoutNode],
@@ -187,7 +187,7 @@ impl<'a> GridLayouter<'a> {
regions.expand = Spec::new(true, false);
Self {
- ctx,
+ world,
cells,
cols,
rows,
@@ -301,7 +301,7 @@ impl<'a> GridLayouter<'a> {
v.resolve(self.styles).relative_to(self.regions.base.y);
}
- let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0);
+ let frame = node.layout(self.world, &pod, self.styles)?.remove(0);
resolved.set_max(frame.width());
}
}
@@ -371,7 +371,7 @@ impl<'a> GridLayouter<'a> {
}
let mut sizes = node
- .layout(self.ctx, &pod, self.styles)?
+ .layout(self.world, &pod, self.styles)?
.into_iter()
.map(|frame| frame.height());
@@ -460,7 +460,7 @@ impl<'a> GridLayouter<'a> {
.select(self.regions.base, size);
let pod = Regions::one(size, base, Spec::splat(true));
- let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0);
+ let frame = node.layout(self.world, &pod, self.styles)?.remove(0);
match frame.role() {
Some(Role::ListLabel | Role::ListItemBody) => {
output.apply_role(Role::ListItem)
@@ -508,7 +508,7 @@ impl<'a> GridLayouter<'a> {
}
// Push the layouted frames into the individual output frames.
- let frames = node.layout(self.ctx, &pod, self.styles)?;
+ let frames = node.layout(self.world, &pod, self.styles)?;
for (output, frame) in outputs.iter_mut().zip(frames) {
match frame.role() {
Some(Role::ListLabel | Role::ListItemBody) => {
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index 9d91c641..72235ccd 100644
--- a/src/library/layout/pad.rs
+++ b/src/library/layout/pad.rs
@@ -11,7 +11,7 @@ pub struct PadNode {
#[node]
impl PadNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let all = args.named("rest")?.or(args.find()?);
let x = args.named("x")?;
let y = args.named("y")?;
@@ -28,14 +28,14 @@ impl PadNode {
impl Layout for PadNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
// Layout child into padded regions.
let padding = self.padding.resolve(styles);
let pod = regions.map(|size| shrink(size, padding));
- let mut frames = self.child.layout(ctx, &pod, styles)?;
+ let mut frames = self.child.layout(world, &pod, styles)?;
for frame in &mut frames {
// Apply the padding inversely such that the grown size padded
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index afcc4855..6e43c4ef 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -41,7 +41,7 @@ impl PageNode {
#[property(referenced)]
pub const FOREGROUND: Marginal = Marginal::None;
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::Page(Self(args.expect("body")?)))
}
@@ -57,7 +57,7 @@ impl PageNode {
/// Layout the page run into a sequence of frames, one per page.
pub fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
mut page: usize,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -97,7 +97,7 @@ impl PageNode {
// Layout the child.
let regions = Regions::repeat(size, size, size.map(Length::is_finite));
- let mut frames = child.layout(ctx, &regions, styles)?;
+ let mut frames = child.layout(world, &regions, styles)?;
let header = styles.get(Self::HEADER);
let footer = styles.get(Self::FOOTER);
@@ -126,9 +126,9 @@ impl PageNode {
(Role::Foreground, foreground, Point::zero(), size),
(Role::Background, background, Point::zero(), size),
] {
- if let Some(content) = marginal.resolve(ctx, page)? {
+ if let Some(content) = marginal.resolve(world, page)? {
let pod = Regions::one(area, area, Spec::splat(true));
- let mut sub = content.layout(ctx, &pod, styles)?.remove(0);
+ let mut sub = content.layout(world, &pod, styles)?.remove(0);
sub.apply_role(role);
if role == Role::Background {
@@ -159,7 +159,7 @@ pub struct PagebreakNode;
#[node]
impl PagebreakNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Pagebreak { weak })
}
@@ -178,13 +178,13 @@ pub enum Marginal {
impl Marginal {
/// Resolve the marginal based on the page number.
- pub fn resolve(&self, ctx: &mut Context, page: usize) -> TypResult<Option<Content>> {
+ pub fn resolve(&self, world: &dyn World, page: usize) -> TypResult<Option<Content>> {
Ok(match self {
Self::None => None,
Self::Content(content) => Some(content.clone()),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(page as i64)]);
- Some(func.call_detached(ctx, args)?.display())
+ Some(func.call_detached(world, args)?.display())
}
})
}
diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs
index 4c6d0062..bb3aac2d 100644
--- a/src/library/layout/place.rs
+++ b/src/library/layout/place.rs
@@ -7,7 +7,7 @@ pub struct PlaceNode(pub LayoutNode);
#[node]
impl PlaceNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start)));
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
@@ -21,7 +21,7 @@ impl PlaceNode {
impl Layout for PlaceNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -35,7 +35,7 @@ impl Layout for PlaceNode {
Regions::one(regions.base, regions.base, expand)
};
- let mut frames = self.0.layout(ctx, &pod, styles)?;
+ let mut frames = self.0.layout(world, &pod, styles)?;
// If expansion is off, zero all sizes so that we don't take up any
// space in our parent. Otherwise, respect the expand settings.
diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs
index da4a96b6..e435e60c 100644
--- a/src/library/layout/spacing.rs
+++ b/src/library/layout/spacing.rs
@@ -8,7 +8,7 @@ pub struct HNode;
#[node]
impl HNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Horizontal { amount, weak })
@@ -20,7 +20,7 @@ pub struct VNode;
#[node]
impl VNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Vertical { amount, weak, generated: false })
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index d8dc0e1a..d07dc35e 100644
--- a/src/library/layout/stack.rs
+++ b/src/library/layout/stack.rs
@@ -15,7 +15,7 @@ pub struct StackNode {
#[node]
impl StackNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::block(Self {
dir: args.named("dir")?.unwrap_or(Dir::TTB),
spacing: args.named("spacing")?,
@@ -27,7 +27,7 @@ impl StackNode {
impl Layout for StackNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -47,7 +47,7 @@ impl Layout for StackNode {
layouter.layout_spacing(kind);
}
- layouter.layout_node(ctx, node, styles)?;
+ layouter.layout_node(world, node, styles)?;
deferred = self.spacing;
}
}
@@ -168,7 +168,7 @@ impl<'a> StackLayouter<'a> {
/// Layout an arbitrary node.
pub fn layout_node(
&mut self,
- ctx: &mut Context,
+ world: &dyn World,
node: &LayoutNode,
styles: StyleChain,
) -> TypResult<()> {
@@ -193,7 +193,7 @@ impl<'a> StackLayouter<'a> {
self.dir.start().into()
});
- let frames = node.layout(ctx, &self.regions, styles)?;
+ let frames = node.layout(world, &self.regions, styles)?;
let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role.
diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs
index 81593c4f..ed98ab1c 100644
--- a/src/library/math/mod.rs
+++ b/src/library/math/mod.rs
@@ -28,7 +28,7 @@ impl MathNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
formula: args.expect("formula")?,
display: args.named("display")?.unwrap_or(false),
@@ -48,7 +48,7 @@ impl Show for MathNode {
}
}
- fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> {
let node = self::rex::RexNode {
tex: self.formula.clone(),
display: self.display,
@@ -64,7 +64,7 @@ impl Show for MathNode {
fn finalize(
&self,
- _: &mut Context,
+ _: &dyn World,
styles: StyleChain,
mut realized: Content,
) -> TypResult<Content> {
diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs
index 0116b4b2..7bfdeb7a 100644
--- a/src/library/math/rex.rs
+++ b/src/library/math/rex.rs
@@ -22,17 +22,16 @@ pub struct RexNode {
impl Layout for RexNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
_: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
// Load the font.
let span = self.tex.span;
- let font = ctx
- .loader
+ let font = world
.book()
.select(self.family.as_str(), variant(styles))
- .and_then(|id| ctx.loader.font(id).ok())
+ .and_then(|id| world.font(id).ok())
.ok_or("failed to find math font")
.at(span)?;
diff --git a/src/library/prelude.rs b/src/library/prelude.rs
index 8bd3b815..a69d9791 100644
--- a/src/library/prelude.rs
+++ b/src/library/prelude.rs
@@ -12,16 +12,15 @@ pub use crate::diag::{
failed_to_load, with_alternative, At, Error, StrResult, TypError, TypResult,
};
pub use crate::eval::{
- Arg, Args, Array, Cast, Dict, Dynamic, Func, Machine, Node, RawAlign, RawLength,
- RawStroke, Scope, Smart, Value,
+ Arg, Args, Array, Cast, Dict, Dynamic, Func, Node, RawAlign, RawLength, RawStroke,
+ Scope, Smart, Value, Vm,
};
pub use crate::frame::*;
pub use crate::geom::*;
-pub use crate::loading::Loader;
pub use crate::model::{
Content, Fold, Key, Layout, LayoutNode, Regions, Resolve, Selector, Show, ShowNode,
StyleChain, StyleMap, StyleVec,
};
pub use crate::syntax::{Span, Spanned};
pub use crate::util::EcoString;
-pub use crate::Context;
+pub use crate::World;
diff --git a/src/library/structure/doc.rs b/src/library/structure/doc.rs
index 80472e24..cabdb4dc 100644
--- a/src/library/structure/doc.rs
+++ b/src/library/structure/doc.rs
@@ -7,11 +7,11 @@ pub struct DocNode(pub StyleVec<PageNode>);
impl DocNode {
/// Layout the document into a sequence of frames, one per page.
- pub fn layout(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Vec<Frame>> {
+ pub fn layout(&self, world: &dyn World, styles: StyleChain) -> TypResult<Vec<Frame>> {
let mut frames = vec![];
for (page, map) in self.0.iter() {
let number = 1 + frames.len();
- frames.extend(page.layout(ctx, number, map.chain(&styles))?);
+ frames.extend(page.layout(world, number, map.chain(&styles))?);
}
Ok(frames)
}
diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs
index 24054f81..c177481f 100644
--- a/src/library/structure/heading.rs
+++ b/src/library/structure/heading.rs
@@ -60,7 +60,7 @@ impl HeadingNode {
/// Whether the heading is numbered.
pub const NUMBERED: bool = true;
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
body: args.expect("body")?,
level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()),
@@ -82,19 +82,19 @@ impl Show for HeadingNode {
}
}
- fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> {
Ok(Content::block(self.body.clone()))
}
fn finalize(
&self,
- ctx: &mut Context,
+ world: &dyn World,
styles: StyleChain,
mut realized: Content,
) -> TypResult<Content> {
macro_rules! resolve {
($key:expr) => {
- styles.get($key).resolve(ctx, self.level)?
+ styles.get($key).resolve(world, self.level)?
};
}
@@ -149,13 +149,13 @@ pub enum Leveled<T> {
impl<T: Cast + Clone> Leveled<T> {
/// Resolve the value based on the level.
- pub fn resolve(&self, ctx: &mut Context, level: NonZeroUsize) -> TypResult<T> {
+ pub fn resolve(&self, world: &dyn World, level: NonZeroUsize) -> TypResult<T> {
Ok(match self {
Self::Value(value) => value.clone(),
Self::Mapping(mapping) => mapping(level),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(level.get() as i64)]);
- func.call_detached(ctx, args)?.cast().at(*span)?
+ func.call_detached(world, args)?.cast().at(*span)?
}
})
}
diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs
index c4167cf9..e9365cd6 100644
--- a/src/library/structure/list.rs
+++ b/src/library/structure/list.rs
@@ -56,7 +56,7 @@ impl<const L: ListKind> ListNode<L> {
#[property(resolve)]
pub const SPACING: BlockSpacing = Ratio::one().into();
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
start: args.named("start")?.unwrap_or(1),
tight: args.named("tight")?.unwrap_or(true),
@@ -100,7 +100,7 @@ impl<const L: ListKind> Show for ListNode<L> {
}
}
- fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> {
let mut cells = vec![];
let mut number = self.start;
@@ -112,7 +112,7 @@ impl<const L: ListKind> Show for ListNode<L> {
cells.push(LayoutNode::default());
cells.push(
label
- .resolve(ctx, L, number)?
+ .resolve(world, L, number)?
.styled_with_map(map.clone())
.role(Role::ListLabel)
.pack(),
@@ -145,7 +145,7 @@ impl<const L: ListKind> Show for ListNode<L> {
fn finalize(
&self,
- _: &mut Context,
+ _: &dyn World,
styles: StyleChain,
realized: Content,
) -> TypResult<Content> {
@@ -208,7 +208,7 @@ impl Label {
/// Resolve the value based on the level.
pub fn resolve(
&self,
- ctx: &mut Context,
+ world: &dyn World,
kind: ListKind,
number: usize,
) -> TypResult<Content> {
@@ -225,7 +225,7 @@ impl Label {
Self::Content(content) => content.clone(),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(number as i64)]);
- func.call_detached(ctx, args)?.display()
+ func.call_detached(world, args)?.display()
}
})
}
diff --git a/src/library/structure/reference.rs b/src/library/structure/reference.rs
index 0eeb4bf5..22dbec01 100644
--- a/src/library/structure/reference.rs
+++ b/src/library/structure/reference.rs
@@ -6,7 +6,7 @@ pub struct RefNode(pub EcoString);
#[node(showable)]
impl RefNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("label")?)))
}
}
@@ -22,7 +22,7 @@ impl Show for RefNode {
}
}
- fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> {
Ok(Content::Text(format_eco!("@{}", self.0)))
}
}
diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs
index 0f74fc96..08fa5386 100644
--- a/src/library/structure/table.rs
+++ b/src/library/structure/table.rs
@@ -30,7 +30,7 @@ impl TableNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
@@ -72,7 +72,7 @@ impl Show for TableNode {
}
}
- fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> {
let fill = styles.get(Self::FILL);
let stroke = styles.get(Self::STROKE).map(RawStroke::unwrap_or_default);
let padding = styles.get(Self::PADDING);
@@ -92,7 +92,7 @@ impl Show for TableNode {
let x = i % cols;
let y = i / cols;
- if let Some(fill) = fill.resolve(ctx, x, y)? {
+ if let Some(fill) = fill.resolve(world, x, y)? {
child = child.filled(fill);
}
@@ -110,7 +110,7 @@ impl Show for TableNode {
fn finalize(
&self,
- _: &mut Context,
+ _: &dyn World,
styles: StyleChain,
realized: Content,
) -> TypResult<Content> {
@@ -129,12 +129,12 @@ pub enum Celled<T> {
impl<T: Cast + Clone> Celled<T> {
/// Resolve the value based on the cell position.
- pub fn resolve(&self, ctx: &mut Context, x: usize, y: usize) -> TypResult<T> {
+ pub fn resolve(&self, world: &dyn World, x: usize, y: usize) -> TypResult<T> {
Ok(match self {
Self::Value(value) => value.clone(),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(x as i64), Value::Int(y as i64)]);
- func.call_detached(ctx, args)?.cast().at(*span)?
+ func.call_detached(world, args)?.cast().at(*span)?
}
})
}
diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs
index 8295f1a2..c58148b4 100644
--- a/src/library/text/deco.rs
+++ b/src/library/text/deco.rs
@@ -34,7 +34,7 @@ impl<const L: DecoLine> DecoNode<L> {
/// with the glyphs. Does not apply to strikethrough.
pub const EVADE: bool = true;
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}
@@ -48,7 +48,7 @@ impl<const L: DecoLine> Show for DecoNode<L> {
dict! { "body" => Value::Content(self.0.clone()) }
}
- fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> {
Ok(self.0.clone().styled(TextNode::DECO, Decoration {
line: L,
stroke: styles.get(Self::STROKE).unwrap_or_default(),
diff --git a/src/library/text/link.rs b/src/library/text/link.rs
index c4898eb0..7d5c3109 100644
--- a/src/library/text/link.rs
+++ b/src/library/text/link.rs
@@ -18,7 +18,7 @@ impl LinkNode {
/// Whether to underline the link.
pub const UNDERLINE: Smart<bool> = Smart::Auto;
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show({
let dest = args.expect::<Destination>("destination")?;
let body = match dest {
@@ -64,7 +64,7 @@ impl Show for LinkNode {
}
}
- fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> {
Ok(self.body.clone().unwrap_or_else(|| match &self.dest {
Destination::Url(url) => {
let mut text = url.as_str();
@@ -80,7 +80,7 @@ impl Show for LinkNode {
fn finalize(
&self,
- _: &mut Context,
+ _: &dyn World,
styles: StyleChain,
mut realized: Content,
) -> TypResult<Content> {
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index 35780186..be586874 100644
--- a/src/library/text/mod.rs
+++ b/src/library/text/mod.rs
@@ -128,7 +128,7 @@ impl TextNode {
#[property(skip, fold)]
pub const DECO: Decoration = vec![];
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
// The text constructor is special: It doesn't create a text node.
// Instead, it leaves the passed argument structurally unchanged, but
// styles all text in it.
@@ -422,12 +422,12 @@ impl Fold for Vec<(Tag, u32)> {
}
/// Convert a string or content to lowercase.
-pub fn lower(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn lower(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
case(Case::Lower, args)
}
/// Convert a string or content to uppercase.
-pub fn upper(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn upper(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
case(Case::Upper, args)
}
@@ -461,7 +461,7 @@ impl Case {
}
/// Display text in small capitals.
-pub fn smallcaps(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn smallcaps(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let body: Content = args.expect("content")?;
Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true)))
}
@@ -493,7 +493,7 @@ pub struct StrongNode(pub Content);
#[node(showable)]
impl StrongNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}
@@ -507,7 +507,7 @@ impl Show for StrongNode {
dict! { "body" => Value::Content(self.0.clone()) }
}
- fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> {
Ok(self.0.clone().styled(TextNode::BOLD, Toggle))
}
}
@@ -518,7 +518,7 @@ pub struct EmphNode(pub Content);
#[node(showable)]
impl EmphNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}
@@ -532,7 +532,7 @@ impl Show for EmphNode {
dict! { "body" => Value::Content(self.0.clone()) }
}
- fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> {
Ok(self.0.clone().styled(TextNode::ITALIC, Toggle))
}
}
diff --git a/src/library/text/par.rs b/src/library/text/par.rs
index 8309bcc8..e8282ef1 100644
--- a/src/library/text/par.rs
+++ b/src/library/text/par.rs
@@ -49,7 +49,7 @@ impl ParNode {
#[property(resolve)]
pub const LINEBREAKS: Smart<Linebreaks> = Smart::Auto;
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
// The paragraph constructor is special: It doesn't create a paragraph
// node. Instead, it just ensures that the passed content lives is in a
// separate paragraph and styles it.
@@ -64,7 +64,7 @@ impl ParNode {
impl Layout for ParNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -74,13 +74,13 @@ impl Layout for ParNode {
// 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(ctx, self, &text, segments, regions, styles)?;
+ let p = prepare(world, self, &text, segments, regions, styles)?;
// Break the paragraph into lines.
- let lines = linebreak(&p, ctx.loader.as_ref(), regions.first.x);
+ let lines = linebreak(&p, world, regions.first.x);
// Stack the lines into one frame per region.
- stack(&p, ctx, &lines, regions)
+ stack(&p, world, &lines, regions)
}
}
@@ -170,7 +170,7 @@ pub struct ParbreakNode;
#[node]
impl ParbreakNode {
- fn construct(_: &mut Machine, _: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Content> {
Ok(Content::Parbreak)
}
}
@@ -180,7 +180,7 @@ pub struct LinebreakNode;
#[node]
impl LinebreakNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
let justified = args.named("justified")?.unwrap_or(false);
Ok(Content::Linebreak { justified })
}
@@ -496,7 +496,7 @@ fn collect<'a>(
/// Prepare paragraph layout by shaping the whole paragraph and layouting all
/// contained inline-level nodes.
fn prepare<'a>(
- ctx: &mut Context,
+ world: &dyn World,
par: &'a ParNode,
text: &'a str,
segments: Vec<(Segment<'a>, StyleChain<'a>)>,
@@ -517,13 +517,7 @@ fn prepare<'a>(
let end = cursor + segment.len();
match segment {
Segment::Text(_) => {
- shape_range(
- &mut items,
- ctx.loader.as_ref(),
- &bidi,
- cursor .. end,
- styles,
- );
+ shape_range(&mut items, world, &bidi, cursor .. end, styles);
}
Segment::Spacing(spacing) => match spacing {
Spacing::Relative(v) => {
@@ -540,7 +534,7 @@ fn prepare<'a>(
} else {
let size = Size::new(regions.first.x, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::splat(false));
- let mut frame = node.layout(ctx, &pod, styles)?.remove(0);
+ let mut frame = node.layout(world, &pod, styles)?.remove(0);
frame.translate(Point::with_y(styles.get(TextNode::BASELINE)));
frame.apply_role(Role::GenericInline);
items.push(Item::Frame(frame));
@@ -567,14 +561,14 @@ fn prepare<'a>(
/// items for them.
fn shape_range<'a>(
items: &mut Vec<Item<'a>>,
- loader: &dyn Loader,
+ world: &dyn World,
bidi: &BidiInfo<'a>,
range: Range,
styles: StyleChain<'a>,
) {
let mut process = |text, level: Level| {
let dir = if level.is_ltr() { Dir::LTR } else { Dir::RTL };
- let shaped = shape(loader, text, styles, dir);
+ let shaped = shape(world, text, styles, dir);
items.push(Item::Text(shaped));
};
@@ -633,12 +627,12 @@ fn shared_get<'a, K: Key<'a>>(
/// Find suitable linebreaks.
fn linebreak<'a>(
p: &'a Preparation<'a>,
- loader: &dyn Loader,
+ world: &dyn World,
width: Length,
) -> Vec<Line<'a>> {
match p.styles.get(ParNode::LINEBREAKS) {
- Linebreaks::Simple => linebreak_simple(p, loader, width),
- Linebreaks::Optimized => linebreak_optimized(p, loader, width),
+ Linebreaks::Simple => linebreak_simple(p, world, width),
+ Linebreaks::Optimized => linebreak_optimized(p, world, width),
}
}
@@ -647,7 +641,7 @@ fn linebreak<'a>(
/// very unbalanced line, but is fast and simple.
fn linebreak_simple<'a>(
p: &'a Preparation<'a>,
- loader: &dyn Loader,
+ world: &dyn World,
width: Length,
) -> Vec<Line<'a>> {
let mut lines = vec![];
@@ -656,7 +650,7 @@ fn linebreak_simple<'a>(
for (end, mandatory, hyphen) in breakpoints(p) {
// Compute the line and its size.
- let mut attempt = line(p, loader, start .. end, mandatory, hyphen);
+ let mut attempt = line(p, world, start .. end, mandatory, hyphen);
// 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
@@ -665,7 +659,7 @@ fn linebreak_simple<'a>(
if let Some((last_attempt, last_end)) = last.take() {
lines.push(last_attempt);
start = last_end;
- attempt = line(p, loader, start .. end, mandatory, hyphen);
+ attempt = line(p, world, start .. end, mandatory, hyphen);
}
}
@@ -707,7 +701,7 @@ fn linebreak_simple<'a>(
/// text.
fn linebreak_optimized<'a>(
p: &'a Preparation<'a>,
- loader: &dyn Loader,
+ world: &dyn World,
width: Length,
) -> Vec<Line<'a>> {
/// The cost of a line or paragraph layout.
@@ -732,7 +726,7 @@ fn linebreak_optimized<'a>(
let mut table = vec![Entry {
pred: 0,
total: 0.0,
- line: line(p, loader, 0 .. 0, false, false),
+ line: line(p, world, 0 .. 0, false, false),
}];
let em = p.styles.get(TextNode::SIZE);
@@ -746,7 +740,7 @@ fn linebreak_optimized<'a>(
for (i, pred) in table.iter_mut().enumerate().skip(active) {
// Layout the line.
let start = pred.line.end;
- let attempt = line(p, loader, start .. end, mandatory, hyphen);
+ let attempt = line(p, world, start .. end, mandatory, hyphen);
// Determine how much the line's spaces would need to be stretched
// to make it the desired width.
@@ -920,7 +914,7 @@ impl Breakpoints<'_> {
/// Create a line which spans the given range.
fn line<'a>(
p: &'a Preparation,
- loader: &dyn Loader,
+ world: &dyn World,
mut range: Range,
mandatory: bool,
hyphen: bool,
@@ -975,9 +969,9 @@ fn line<'a>(
if hyphen || start + shaped.text.len() > range.end {
if hyphen || start < range.end || before.is_empty() {
let shifted = start - base .. range.end - base;
- let mut reshaped = shaped.reshape(loader, shifted);
+ let mut reshaped = shaped.reshape(world, shifted);
if hyphen || shy {
- reshaped.push_hyphen(loader);
+ reshaped.push_hyphen(world);
}
width += reshaped.width;
last = Some(Item::Text(reshaped));
@@ -998,7 +992,7 @@ fn line<'a>(
if range.start + shaped.text.len() > end {
if range.start < end {
let shifted = range.start - base .. end - base;
- let reshaped = shaped.reshape(loader, shifted);
+ let reshaped = shaped.reshape(world, shifted);
width += reshaped.width;
first = Some(Item::Text(reshaped));
}
@@ -1028,7 +1022,7 @@ fn line<'a>(
/// Combine layouted lines into one frame per region.
fn stack(
p: &Preparation,
- ctx: &mut Context,
+ world: &dyn World,
lines: &[Line],
regions: &Regions,
) -> TypResult<Vec<Frame>> {
@@ -1048,7 +1042,7 @@ fn stack(
// Stack the lines into one frame per region.
for line in lines {
- let frame = commit(p, ctx, line, &regions, width)?;
+ let frame = commit(p, world, line, &regions, width)?;
let height = frame.size().y;
while !regions.first.y.fits(height) && !regions.in_last() {
@@ -1078,7 +1072,7 @@ fn stack(
/// Commit to a line and build its frame.
fn commit(
p: &Preparation,
- ctx: &mut Context,
+ world: &dyn World,
line: &Line,
regions: &Regions,
width: Length,
@@ -1149,7 +1143,7 @@ fn commit(
offset += v.share(fr, remaining);
}
Item::Text(shaped) => {
- let frame = shaped.build(ctx.loader.as_ref(), justification);
+ let frame = shaped.build(world, justification);
push(&mut offset, frame);
}
Item::Frame(frame) => {
@@ -1160,7 +1154,7 @@ fn commit(
let fill = Fraction::one().share(fr, remaining);
let size = Size::new(fill, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::new(false, false));
- let frame = node.layout(ctx, &pod, *styles)?.remove(0);
+ let frame = node.layout(world, &pod, *styles)?.remove(0);
let width = frame.width();
let count = (fill / width).floor();
let remaining = fill % width;
diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs
index a2a57fa1..c729fa40 100644
--- a/src/library/text/raw.rs
+++ b/src/library/text/raw.rs
@@ -35,7 +35,7 @@ impl RawNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
text: args.expect("text")?,
block: args.named("block")?.unwrap_or(false),
@@ -59,7 +59,7 @@ impl Show for RawNode {
}
}
- fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> {
let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase());
let foreground = THEME
.settings
@@ -111,7 +111,7 @@ impl Show for RawNode {
fn finalize(
&self,
- _: &mut Context,
+ _: &dyn World,
styles: StyleChain,
mut realized: Content,
) -> TypResult<Content> {
diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs
index aca281fc..c2a0de70 100644
--- a/src/library/text/repeat.rs
+++ b/src/library/text/repeat.rs
@@ -6,7 +6,7 @@ pub struct RepeatNode(pub LayoutNode);
#[node]
impl RepeatNode {
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}
@@ -14,11 +14,11 @@ impl RepeatNode {
impl Layout for RepeatNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
// The actual repeating happens directly in the paragraph.
- self.0.layout(ctx, regions, styles)
+ self.0.layout(world, regions, styles)
}
}
diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs
index 3d905c99..6e505702 100644
--- a/src/library/text/shaping.rs
+++ b/src/library/text/shaping.rs
@@ -80,8 +80,8 @@ impl<'a> ShapedText<'a> {
///
/// The `justification` defines how much extra advance width each
/// [justifiable glyph](ShapedGlyph::is_justifiable) will get.
- pub fn build(&self, loader: &dyn Loader, justification: Length) -> Frame {
- let (top, bottom) = self.measure(loader);
+ pub fn build(&self, world: &dyn World, justification: Length) -> Frame {
+ let (top, bottom) = self.measure(world);
let size = Size::new(self.width, top + bottom);
let mut offset = Length::zero();
@@ -144,7 +144,7 @@ impl<'a> ShapedText<'a> {
}
/// Measure the top and bottom extent of this text.
- fn measure(&self, loader: &dyn Loader) -> (Length, Length) {
+ fn measure(&self, world: &dyn World) -> (Length, Length) {
let mut top = Length::zero();
let mut bottom = Length::zero();
@@ -162,10 +162,10 @@ impl<'a> ShapedText<'a> {
// When there are no glyphs, we just use the vertical metrics of the
// first available font.
for family in families(self.styles) {
- if let Some(font) = loader
+ if let Some(font) = world
.book()
.select(family, self.variant)
- .and_then(|id| loader.font(id).ok())
+ .and_then(|id| world.font(id).ok())
{
expand(&font);
break;
@@ -199,7 +199,7 @@ impl<'a> ShapedText<'a> {
/// shaping process if possible.
pub fn reshape(
&'a self,
- loader: &dyn Loader,
+ world: &dyn World,
text_range: Range<usize>,
) -> ShapedText<'a> {
if let Some(glyphs) = self.slice_safe_to_break(text_range.clone()) {
@@ -213,17 +213,17 @@ impl<'a> ShapedText<'a> {
glyphs: Cow::Borrowed(glyphs),
}
} else {
- shape(loader, &self.text[text_range], self.styles, self.dir)
+ shape(world, &self.text[text_range], self.styles, self.dir)
}
}
/// Push a hyphen to end of the text.
- pub fn push_hyphen(&mut self, loader: &dyn Loader) {
+ pub fn push_hyphen(&mut self, world: &dyn World) {
families(self.styles).find_map(|family| {
- let font = loader
+ let font = world
.book()
.select(family, self.variant)
- .and_then(|id| loader.font(id).ok())?;
+ .and_then(|id| world.font(id).ok())?;
let ttf = font.ttf();
let glyph_id = ttf.glyph_index('-')?;
let x_advance = font.to_em(ttf.glyph_hor_advance(glyph_id)?);
@@ -306,7 +306,7 @@ impl Debug for ShapedText<'_> {
/// Holds shaping results and metadata common to all shaped segments.
struct ShapingContext<'a> {
- loader: &'a dyn Loader,
+ world: &'a dyn World,
glyphs: Vec<ShapedGlyph>,
used: Vec<Font>,
styles: StyleChain<'a>,
@@ -319,7 +319,7 @@ struct ShapingContext<'a> {
/// Shape text into [`ShapedText`].
pub fn shape<'a>(
- loader: &dyn Loader,
+ world: &dyn World,
text: &'a str,
styles: StyleChain<'a>,
dir: Dir,
@@ -327,7 +327,7 @@ pub fn shape<'a>(
let size = styles.get(TextNode::SIZE);
let mut ctx = ShapingContext {
- loader,
+ world,
size,
glyphs: vec![],
used: vec![],
@@ -368,10 +368,10 @@ fn shape_segment<'a>(
}
// Find the next available family.
- let book = ctx.loader.book();
+ let book = ctx.world.book();
let mut selection = families.find_map(|family| {
book.select(family, ctx.variant)
- .and_then(|id| ctx.loader.font(id).ok())
+ .and_then(|id| ctx.world.font(id).ok())
.filter(|font| !ctx.used.contains(font))
});
@@ -380,7 +380,7 @@ fn shape_segment<'a>(
let first = ctx.used.first().map(Font::info);
selection = book
.select_fallback(first, ctx.variant, text)
- .and_then(|id| ctx.loader.font(id).ok())
+ .and_then(|id| ctx.world.font(id).ok())
.filter(|font| !ctx.used.contains(font));
}
diff --git a/src/library/text/shift.rs b/src/library/text/shift.rs
index 75b2a579..5da36da1 100644
--- a/src/library/text/shift.rs
+++ b/src/library/text/shift.rs
@@ -28,7 +28,7 @@ impl<const S: ScriptKind> ShiftNode<S> {
/// The font size for synthetic sub- and superscripts.
pub const SIZE: TextSize = TextSize(Em::new(0.6).into());
- fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
+ fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}
@@ -42,11 +42,11 @@ impl<const S: ScriptKind> Show for ShiftNode<S> {
dict! { "body" => Value::Content(self.0.clone()) }
}
- fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
+ fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> {
let mut transformed = None;
if styles.get(Self::TYPOGRAPHIC) {
if let Some(text) = search_text(&self.0, S) {
- if is_shapable(ctx.loader.as_ref(), &text, styles) {
+ if is_shapable(world, &text, styles) {
transformed = Some(Content::Text(text));
}
}
@@ -91,12 +91,12 @@ fn search_text(content: &Content, mode: ScriptKind) -> Option<EcoString> {
/// Checks whether the first retrievable family contains all code points of the
/// given string.
-fn is_shapable(loader: &dyn Loader, text: &str, styles: StyleChain) -> bool {
- let book = loader.book();
+fn is_shapable(world: &dyn World, text: &str, styles: StyleChain) -> bool {
for family in styles.get(TextNode::FAMILY).iter() {
- if let Some(font) = book
+ if let Some(font) = world
+ .book()
.select(family.as_str(), variant(styles))
- .and_then(|id| loader.font(id).ok())
+ .and_then(|id| world.font(id).ok())
{
return text.chars().all(|c| font.ttf().glyph_index(c).is_some());
}
diff --git a/src/library/utility/color.rs b/src/library/utility/color.rs
index 7c6ed873..a7d55d1c 100644
--- a/src/library/utility/color.rs
+++ b/src/library/utility/color.rs
@@ -3,13 +3,13 @@ use std::str::FromStr;
use crate::library::prelude::*;
/// Create a grayscale color.
-pub fn luma(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn luma(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Component(luma) = args.expect("gray component")?;
Ok(Value::Color(LumaColor::new(luma).into()))
}
/// Create an RGB(A) color.
-pub fn rgb(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
Ok(Value::Color(
if let Some(string) = args.find::<Spanned<EcoString>>()? {
match RgbaColor::from_str(&string.v) {
@@ -27,7 +27,7 @@ pub fn rgb(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// Create a CMYK color.
-pub fn cmyk(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn cmyk(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let RatioComponent(c) = args.expect("cyan component")?;
let RatioComponent(m) = args.expect("magenta component")?;
let RatioComponent(y) = args.expect("yellow component")?;
diff --git a/src/library/utility/data.rs b/src/library/utility/data.rs
index f9e970dc..59f3d351 100644
--- a/src/library/utility/data.rs
+++ b/src/library/utility/data.rs
@@ -1,13 +1,13 @@
use crate::library::prelude::*;
/// Read structured data from a CSV file.
-pub fn csv(vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn csv(vm: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to csv file")?;
let path = vm.locate(&path).at(span)?;
let try_load = || -> io::Result<Value> {
- let data = vm.ctx.loader.file(&path)?;
+ let data = vm.world.file(&path)?;
let mut builder = csv::ReaderBuilder::new();
builder.has_headers(false);
diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs
index f68cc1bf..47648282 100644
--- a/src/library/utility/math.rs
+++ b/src/library/utility/math.rs
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
use crate::library::prelude::*;
/// Convert a value to an integer.
-pub fn int(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Int(match v {
Value::Bool(v) => v as i64,
@@ -18,7 +18,7 @@ pub fn int(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// Convert a value to a float.
-pub fn float(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Float(match v {
Value::Int(v) => v as f64,
@@ -32,7 +32,7 @@ pub fn float(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// The absolute value of a numeric value.
-pub fn abs(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("numeric value")?;
Ok(match v {
Value::Int(v) => Value::Int(v.abs()),
@@ -48,12 +48,12 @@ pub fn abs(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// The minimum of a sequence of values.
-pub fn min(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn min(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
minmax(args, Ordering::Less)
}
/// The maximum of a sequence of values.
-pub fn max(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn max(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
minmax(args, Ordering::Greater)
}
@@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> {
}
/// Whether an integer is even.
-pub fn even(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn even(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
}
/// Whether an integer is odd.
-pub fn odd(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn odd(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
}
/// The modulo of two numbers.
-pub fn mod_(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn mod_(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
@@ -119,7 +119,7 @@ pub fn mod_(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// Create a sequence of numbers.
-pub fn range(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn range(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let first = args.expect::<i64>("end")?;
let (start, end) = match args.eat::<i64>()? {
Some(second) => (first, second),
diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs
index bc7c6f25..40a107ba 100644
--- a/src/library/utility/mod.rs
+++ b/src/library/utility/mod.rs
@@ -10,17 +10,17 @@ pub use data::*;
pub use math::*;
pub use string::*;
-use crate::eval::{Eval, Machine, Scopes};
+use crate::eval::{Eval, Scopes, Vm};
use crate::library::prelude::*;
use crate::source::Source;
/// The name of a value's type.
-pub fn type_(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn type_(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
Ok(args.expect::<Value>("value")?.type_name().into())
}
/// Ensure that a condition is fulfilled.
-pub fn assert(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
if !v {
bail!(span, "assertion failed");
@@ -29,19 +29,18 @@ pub fn assert(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// Evaluate a string as Typst markup.
-pub fn eval(vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
- let Spanned { v: src, span } = args.expect::<Spanned<String>>("source")?;
+pub fn eval(vm: &mut Vm, args: &mut Args) -> TypResult<Value> {
+ let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
// Parse the source and set a synthetic span for all nodes.
- let source = Source::synthesized(src, span);
+ let source = Source::synthesized(text, span);
let ast = source.ast()?;
// Evaluate the source.
- let std = vm.ctx.config.std.clone();
- let scopes = Scopes::new(Some(&std));
- let mut sub = Machine::new(vm.ctx, vec![], scopes);
+ let std = &vm.world.config().std;
+ let scopes = Scopes::new(Some(std));
+ let mut sub = Vm::new(vm.world, vec![], scopes);
let result = ast.eval(&mut sub);
- assert!(vm.deps.is_empty());
// Handle control flow.
if let Some(flow) = sub.flow {
diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs
index 972b44d7..d825d84b 100644
--- a/src/library/utility/string.rs
+++ b/src/library/utility/string.rs
@@ -2,12 +2,12 @@ use crate::eval::Regex;
use crate::library::prelude::*;
/// The string representation of a value.
-pub fn repr(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn repr(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
Ok(args.expect::<Value>("value")?.repr().into())
}
/// Convert a value to a string.
-pub fn str(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Str(match v {
Value::Int(v) => format_str!("{}", v),
@@ -18,29 +18,29 @@ pub fn str(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
}
/// Create blind text.
-pub fn lorem(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn lorem(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let words: usize = args.expect("number of words")?;
Ok(Value::Str(lipsum::lipsum(words).into()))
}
/// Create a regular expression.
-pub fn regex(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn regex(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?;
Ok(Regex::new(&v).at(span)?.into())
}
/// Converts an integer into one or multiple letters.
-pub fn letter(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn letter(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
numbered(Numbering::Letter, args)
}
/// Converts an integer into a roman numeral.
-pub fn roman(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn roman(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
numbered(Numbering::Roman, args)
}
/// Convert a number into a symbol.
-pub fn symbol(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
+pub fn symbol(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
numbered(Numbering::Symbol, args)
}
diff --git a/src/loading.rs b/src/loading.rs
deleted file mode 100644
index 9a32d025..00000000
--- a/src/loading.rs
+++ /dev/null
@@ -1,239 +0,0 @@
-//! Resource loading.
-
-use std::fmt::{self, Debug, Formatter};
-use std::io;
-use std::ops::Deref;
-use std::path::Path;
-use std::sync::Arc;
-
-use crate::font::{Font, FontBook};
-use crate::util::Prehashed;
-
-/// A hash that identifies a file.
-///
-/// Such a hash can be [resolved](Loader::resolve) from a path.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct FileHash(pub u64);
-
-/// Loads resources from a local or remote source.
-pub trait Loader {
- /// Metadata about all known fonts.
- fn book(&self) -> &FontBook;
-
- /// Access the font with the given id.
- fn font(&self, id: usize) -> io::Result<Font>;
-
- /// Resolve a hash that is the same for this and all other paths pointing to
- /// the same file.
- fn resolve(&self, path: &Path) -> io::Result<FileHash>;
-
- /// Load a file from a path.
- fn file(&self, path: &Path) -> io::Result<Buffer>;
-}
-
-/// A shared buffer that is cheap to clone.
-#[derive(Clone, Hash, Eq, PartialEq)]
-pub struct Buffer(Prehashed<Arc<Vec<u8>>>);
-
-impl Buffer {
- /// Return a view into the buffer.
- pub fn as_slice(&self) -> &[u8] {
- self
- }
-
- /// Return a copy of the buffer as a vector.
- pub fn to_vec(&self) -> Vec<u8> {
- self.0.to_vec()
- }
-}
-
-impl From<&[u8]> for Buffer {
- fn from(slice: &[u8]) -> Self {
- Self(Prehashed::new(Arc::new(slice.to_vec())))
- }
-}
-
-impl From<Vec<u8>> for Buffer {
- fn from(vec: Vec<u8>) -> Self {
- Self(Prehashed::new(Arc::new(vec)))
- }
-}
-
-impl From<Arc<Vec<u8>>> for Buffer {
- fn from(arc: Arc<Vec<u8>>) -> Self {
- Self(Prehashed::new(arc))
- }
-}
-
-impl Deref for Buffer {
- type Target = [u8];
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl AsRef<[u8]> for Buffer {
- fn as_ref(&self) -> &[u8] {
- self
- }
-}
-
-impl Debug for Buffer {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("Buffer(..)")
- }
-}
-
-#[cfg(feature = "fs")]
-pub use fs::*;
-
-#[cfg(feature = "fs")]
-mod fs {
- use std::fs::{self, File};
- use std::io;
- use std::path::{Path, PathBuf};
-
- use memmap2::Mmap;
- use same_file::Handle;
- use walkdir::WalkDir;
-
- use super::{Buffer, FileHash, Loader};
- use crate::font::{Font, FontBook, FontInfo};
-
- /// Loads fonts and files from the local file system.
- ///
- /// _This is only available when the `system` feature is enabled._
- pub struct FsLoader {
- book: FontBook,
- paths: Vec<(PathBuf, u32)>,
- }
-
- impl FsLoader {
- /// Create a new system loader.
- pub fn new() -> Self {
- Self { book: FontBook::new(), paths: vec![] }
- }
-
- /// Builder-style variant of [`search_path`](Self::search_path).
- pub fn with_path(mut self, dir: impl AsRef<Path>) -> Self {
- self.search_path(dir);
- self
- }
-
- /// Search for all fonts at a path.
- ///
- /// If the path is a directory, all contained fonts will be searched for
- /// recursively.
- pub fn search_path(&mut self, path: impl AsRef<Path>) {
- let walk = WalkDir::new(path)
- .follow_links(true)
- .sort_by(|a, b| a.file_name().cmp(b.file_name()))
- .into_iter()
- .filter_map(|e| e.ok());
-
- for entry in walk {
- let path = entry.path();
- if let Some(ext) = path.extension().and_then(|s| s.to_str()) {
- if matches!(
- ext,
- "ttf" | "otf" | "TTF" | "OTF" | "ttc" | "otc" | "TTC" | "OTC",
- ) {
- self.search_file(path);
- }
- }
- }
- }
-
- /// Index the fonts in the file at the given path.
- ///
- /// The file may form a font collection and contain multiple fonts,
- /// which will then all be indexed.
- fn search_file(&mut self, path: impl AsRef<Path>) {
- let path = path.as_ref();
- let path = path.strip_prefix(".").unwrap_or(path);
- if let Ok(file) = File::open(path) {
- if let Ok(mmap) = unsafe { Mmap::map(&file) } {
- for (i, info) in FontInfo::from_data(&mmap).enumerate() {
- self.book.push(info);
- self.paths.push((path.into(), i as u32));
- }
- }
- }
- }
-
- /// Builder-style variant of [`search_system`](Self::search_system).
- pub fn with_system(mut self) -> Self {
- self.search_system();
- self
- }
-
- /// Search for fonts in the operating system's font directories.
- pub fn search_system(&mut self) {
- self.search_system_impl();
- }
-
- #[cfg(all(unix, not(target_os = "macos")))]
- fn search_system_impl(&mut self) {
- self.search_path("/usr/share/fonts");
- self.search_path("/usr/local/share/fonts");
-
- if let Some(dir) = dirs::font_dir() {
- self.search_path(dir);
- }
- }
-
- #[cfg(target_os = "macos")]
- fn search_system_impl(&mut self) {
- self.search_path("/Library/Fonts");
- self.search_path("/Network/Library/Fonts");
- self.search_path("/System/Library/Fonts");
-
- if let Some(dir) = dirs::font_dir() {
- self.search_path(dir);
- }
- }
-
- #[cfg(windows)]
- fn search_system_impl(&mut self) {
- let windir =
- std::env::var("WINDIR").unwrap_or_else(|_| "C:\\Windows".to_string());
-
- self.search_path(Path::new(&windir).join("Fonts"));
-
- if let Some(roaming) = dirs::config_dir() {
- self.search_path(roaming.join("Microsoft\\Windows\\Fonts"));
- }
-
- if let Some(local) = dirs::cache_dir() {
- self.search_path(local.join("Microsoft\\Windows\\Fonts"));
- }
- }
- }
-
- impl Loader for FsLoader {
- fn book(&self) -> &FontBook {
- &self.book
- }
-
- fn font(&self, id: usize) -> io::Result<Font> {
- let (path, index) = &self.paths[id];
- let data = self.file(path)?;
- Font::new(data, *index).ok_or_else(|| io::ErrorKind::InvalidData.into())
- }
-
- fn resolve(&self, path: &Path) -> io::Result<FileHash> {
- let meta = fs::metadata(path)?;
- if meta.is_file() {
- let handle = Handle::from_path(path)?;
- Ok(FileHash(fxhash::hash64(&handle)))
- } else {
- Err(io::ErrorKind::NotFound.into())
- }
- }
-
- fn file(&self, path: &Path) -> io::Result<Buffer> {
- Ok(fs::read(path)?.into())
- }
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 8d6a669a..e5af0d8b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,22 +1,32 @@
-use std::fs;
+use std::cell::RefCell;
+use std::collections::{hash_map::Entry, HashMap};
+use std::fs::{self, File};
+use std::hash::Hash;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
-use std::sync::Arc;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::term::{self, termcolor};
+use elsa::FrozenVec;
+use memmap2::Mmap;
+use once_cell::unsync::OnceCell;
use pico_args::Arguments;
-use same_file::is_same_file;
+use same_file::{is_same_file, Handle};
+use siphasher::sip128::{Hasher128, SipHasher};
use termcolor::{ColorChoice, StandardStream, WriteColor};
+use walkdir::WalkDir;
-use typst::diag::{Error, StrResult};
-use typst::font::FontVariant;
+use typst::diag::{failed_to_load, Error, StrResult};
+use typst::font::{Font, FontBook, FontInfo, FontVariant};
use typst::library::text::THEME;
-use typst::loading::{FsLoader, Loader};
use typst::parse::TokenMode;
-use typst::source::SourceStore;
-use typst::{Config, Context};
+use typst::source::{Source, SourceId};
+use typst::util::Buffer;
+use typst::{Config, World};
+
+type CodespanResult<T> = Result<T, CodespanError>;
+type CodespanError = codespan_reporting::files::Error;
/// What to do.
enum Command {
@@ -191,25 +201,20 @@ fn dispatch(command: Command) -> StrResult<()> {
/// Execute a typesetting command.
fn typeset(command: TypesetCommand) -> StrResult<()> {
- let mut config = Config::builder();
+ let mut world = SystemWorld::new();
if let Some(root) = &command.root {
- config.root(root);
+ world.config.root = root.clone();
} else if let Some(dir) = command.input.parent() {
- config.root(dir);
+ world.config.root = dir.into();
}
- // Create a loader for fonts and files.
- let loader = FsLoader::new().with_system();
-
- // Create the context which holds loaded source files, fonts, images and
- // cached artifacts.
- let mut ctx = Context::new(Arc::new(loader), config.build());
-
- // Load the source file.
- let id = ctx.sources.load(&command.input)?;
+ // Create the world that serves sources, fonts and files.
+ let id = world
+ .resolve(&command.input)
+ .map_err(|err| failed_to_load("source file", &command.input, err))?;
// Typeset.
- match typst::typeset(&mut ctx, id) {
+ match typst::typeset(&world, id) {
// Export the PDF.
Ok(frames) => {
let buffer = typst::export::pdf(&frames);
@@ -218,7 +223,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
// Print diagnostics.
Err(errors) => {
- print_diagnostics(&ctx.sources, *errors)
+ print_diagnostics(&world, *errors)
.map_err(|_| "failed to print diagnostics")?;
}
}
@@ -228,7 +233,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
/// Print diagnostic messages to the terminal.
fn print_diagnostics(
- sources: &SourceStore,
+ world: &SystemWorld,
errors: Vec<Error>,
) -> Result<(), codespan_reporting::files::Error> {
let mut w = StandardStream::stderr(ColorChoice::Always);
@@ -236,21 +241,24 @@ fn print_diagnostics(
for error in errors {
// The main diagnostic.
- let range = sources.range(error.span);
+ let range = world.source(error.span.source()).range(error.span);
let diag = Diagnostic::error()
.with_message(error.message)
.with_labels(vec![Label::primary(error.span.source(), range)]);
- term::emit(&mut w, &config, sources, &diag)?;
+ term::emit(&mut w, &config, world, &diag)?;
// Stacktrace-like helper diagnostics.
for point in error.trace {
let message = point.v.to_string();
let help = Diagnostic::help().with_message(message).with_labels(vec![
- Label::primary(point.span.source(), sources.range(point.span)),
+ Label::primary(
+ point.span.source(),
+ world.source(point.span.source()).range(point.span),
+ ),
]);
- term::emit(&mut w, &config, sources, &help)?;
+ term::emit(&mut w, &config, world, &help)?;
}
}
@@ -259,8 +267,8 @@ fn print_diagnostics(
/// Execute a highlighting command.
fn highlight(command: HighlightCommand) -> StrResult<()> {
- let input = std::fs::read_to_string(&command.input)
- .map_err(|_| "failed to load source file")?;
+ let input =
+ fs::read_to_string(&command.input).map_err(|_| "failed to load source file")?;
let html = typst::syntax::highlight_html(&input, TokenMode::Markup, &THEME);
fs::write(&command.output, html).map_err(|_| "failed to write HTML file")?;
@@ -270,8 +278,8 @@ fn highlight(command: HighlightCommand) -> StrResult<()> {
/// Execute a font listing command.
fn fonts(command: FontsCommand) -> StrResult<()> {
- let loader = FsLoader::new().with_system();
- for (name, infos) in loader.book().families() {
+ let world = SystemWorld::new();
+ for (name, infos) in world.book().families() {
println!("{name}");
if command.variants {
for info in infos {
@@ -283,3 +291,234 @@ fn fonts(command: FontsCommand) -> StrResult<()> {
Ok(())
}
+
+/// A world that provides access to the operating system.
+struct SystemWorld {
+ config: Config,
+ sources: FrozenVec<Box<Source>>,
+ nav: RefCell<HashMap<PathHash, SourceId>>,
+ book: FontBook,
+ fonts: Vec<FontSlot>,
+ files: RefCell<HashMap<PathHash, Buffer>>,
+}
+
+struct FontSlot {
+ path: PathBuf,
+ index: u32,
+ font: OnceCell<Option<Font>>,
+}
+
+impl SystemWorld {
+ fn new() -> Self {
+ let mut world = Self {
+ config: Config::default(),
+ book: FontBook::new(),
+ sources: FrozenVec::new(),
+ nav: RefCell::new(HashMap::new()),
+ fonts: vec![],
+ files: RefCell::new(HashMap::new()),
+ };
+ world.search_system();
+ world
+ }
+}
+
+impl World for SystemWorld {
+ fn config(&self) -> &Config {
+ &self.config
+ }
+
+ fn resolve(&self, path: &Path) -> io::Result<SourceId> {
+ let hash = PathHash::new(path)?;
+ if let Some(&id) = self.nav.borrow().get(&hash) {
+ return Ok(id);
+ }
+
+ let data = fs::read(path)?;
+ let text = String::from_utf8(data).map_err(|_| {
+ io::Error::new(io::ErrorKind::InvalidData, "file is not valid utf-8")
+ })?;
+
+ let id = SourceId::from_raw(self.sources.len() as u16);
+ let source = Source::new(id, path, text);
+ self.sources.push(Box::new(source));
+ self.nav.borrow_mut().insert(hash, id);
+
+ Ok(id)
+ }
+
+ fn source(&self, id: SourceId) -> &Source {
+ &self.sources[id.into_raw() as usize]
+ }
+
+ fn book(&self) -> &FontBook {
+ &self.book
+ }
+
+ fn font(&self, id: usize) -> io::Result<Font> {
+ let slot = &self.fonts[id];
+ slot.font
+ .get_or_init(|| {
+ let data = self.file(&slot.path).ok()?;
+ Font::new(data, slot.index)
+ })
+ .clone()
+ .ok_or_else(|| io::ErrorKind::InvalidData.into())
+ }
+
+ fn file(&self, path: &Path) -> io::Result<Buffer> {
+ let hash = PathHash::new(path)?;
+ Ok(match self.files.borrow_mut().entry(hash) {
+ Entry::Occupied(entry) => entry.get().clone(),
+ Entry::Vacant(entry) => entry.insert(fs::read(path)?.into()).clone(),
+ })
+ }
+}
+
+/// A hash that is the same for all paths pointing to the same file.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+struct PathHash(u128);
+
+impl PathHash {
+ fn new(path: &Path) -> io::Result<Self> {
+ let file = File::open(path)?;
+ if file.metadata()?.is_file() {
+ let handle = Handle::from_file(file)?;
+ let mut state = SipHasher::new();
+ handle.hash(&mut state);
+ Ok(Self(state.finish128().as_u128()))
+ } else {
+ Err(io::ErrorKind::NotFound.into())
+ }
+ }
+}
+
+impl SystemWorld {
+ /// Search for fonts in the linux system font directories.
+ #[cfg(all(unix, not(target_os = "macos")))]
+ fn search_system(&mut self) {
+ self.search_dir("/usr/share/fonts");
+ self.search_dir("/usr/local/share/fonts");
+
+ if let Some(dir) = dirs::font_dir() {
+ self.search_dir(dir);
+ }
+ }
+
+ /// Search for fonts in the macOS system font directories.
+ #[cfg(target_os = "macos")]
+ fn search_system(&mut self) {
+ self.search_dir("/Library/Fonts");
+ self.search_dir("/Network/Library/Fonts");
+ self.search_dir("/System/Library/Fonts");
+
+ if let Some(dir) = dirs::font_dir() {
+ self.search_dir(dir);
+ }
+ }
+
+ /// Search for fonts in the Windows system font directories.
+ #[cfg(windows)]
+ fn search_system(&mut self) {
+ let windir =
+ std::env::var("WINDIR").unwrap_or_else(|_| "C:\\Windows".to_string());
+
+ self.search_dir(Path::new(&windir).join("Fonts"));
+
+ if let Some(roaming) = dirs::config_dir() {
+ self.search_dir(roaming.join("Microsoft\\Windows\\Fonts"));
+ }
+
+ if let Some(local) = dirs::cache_dir() {
+ self.search_dir(local.join("Microsoft\\Windows\\Fonts"));
+ }
+ }
+
+ /// Search for all fonts in a directory.
+ /// recursively.
+ fn search_dir(&mut self, path: impl AsRef<Path>) {
+ for entry in WalkDir::new(path)
+ .follow_links(true)
+ .sort_by(|a, b| a.file_name().cmp(b.file_name()))
+ .into_iter()
+ .filter_map(|e| e.ok())
+ {
+ let path = entry.path();
+ if matches!(
+ path.extension().and_then(|s| s.to_str()),
+ Some("ttf" | "otf" | "TTF" | "OTF" | "ttc" | "otc" | "TTC" | "OTC"),
+ ) {
+ self.search_file(path);
+ }
+ }
+ }
+
+ /// Index the fonts in the file at the given path.
+ fn search_file(&mut self, path: impl AsRef<Path>) {
+ let path = path.as_ref();
+ if let Ok(file) = File::open(path) {
+ if let Ok(mmap) = unsafe { Mmap::map(&file) } {
+ for (i, info) in FontInfo::from_data(&mmap).enumerate() {
+ self.book.push(info);
+ self.fonts.push(FontSlot {
+ path: path.into(),
+ index: i as u32,
+ font: OnceCell::new(),
+ });
+ }
+ }
+ }
+ }
+}
+
+impl<'a> codespan_reporting::files::Files<'a> for SystemWorld {
+ type FileId = SourceId;
+ type Name = std::path::Display<'a>;
+ type Source = &'a str;
+
+ fn name(&'a self, id: SourceId) -> CodespanResult<Self::Name> {
+ Ok(World::source(self, id).path().display())
+ }
+
+ fn source(&'a self, id: SourceId) -> CodespanResult<Self::Source> {
+ Ok(World::source(self, id).text())
+ }
+
+ fn line_index(&'a self, id: SourceId, given: usize) -> CodespanResult<usize> {
+ let source = World::source(self, id);
+ source
+ .byte_to_line(given)
+ .ok_or_else(|| CodespanError::IndexTooLarge {
+ given,
+ max: source.len_bytes(),
+ })
+ }
+
+ fn line_range(
+ &'a self,
+ id: SourceId,
+ given: usize,
+ ) -> CodespanResult<std::ops::Range<usize>> {
+ let source = World::source(self, id);
+ source
+ .line_to_range(given)
+ .ok_or_else(|| CodespanError::LineTooLarge { given, max: source.len_lines() })
+ }
+
+ fn column_number(
+ &'a self,
+ id: SourceId,
+ _: usize,
+ given: usize,
+ ) -> CodespanResult<usize> {
+ let source = World::source(self, id);
+ source.byte_to_column(given).ok_or_else(|| {
+ let max = source.len_bytes();
+ if given <= max {
+ CodespanError::InvalidCharBoundary { given }
+ } else {
+ CodespanError::IndexTooLarge { given, max }
+ }
+ })
+ }
+}
diff --git a/src/model/content.rs b/src/model/content.rs
index ae86e279..8076eff9 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -18,20 +18,20 @@ use crate::library::text::{
DecoNode, EmphNode, ParChild, ParNode, StrongNode, UNDERLINE,
};
use crate::util::EcoString;
+use crate::World;
/// Layout content into a collection of pages.
///
/// Relayouts until all pinned locations are converged.
-pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Frame>> {
- let copy = ctx.config.styles.clone();
- let styles = StyleChain::with_root(&copy);
+pub fn layout(world: &dyn World, content: &Content) -> TypResult<Vec<Frame>> {
+ let styles = StyleChain::with_root(&world.config().styles);
let scratch = Scratch::default();
- let mut builder = Builder::new(ctx, &scratch, true);
+ let mut builder = Builder::new(world, &scratch, true);
builder.accept(content, styles)?;
let (doc, shared) = builder.into_doc(styles)?;
- doc.layout(ctx, shared)
+ doc.layout(world, shared)
}
/// Composable representation of styled content.
@@ -232,15 +232,15 @@ impl Content {
impl Layout for Content {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
let scratch = Scratch::default();
- let mut builder = Builder::new(ctx, &scratch, false);
+ let mut builder = Builder::new(world, &scratch, false);
builder.accept(self, styles)?;
let (flow, shared) = builder.into_flow(styles)?;
- flow.layout(ctx, regions, shared)
+ flow.layout(world, regions, shared)
}
fn pack(self) -> LayoutNode {
@@ -330,9 +330,9 @@ impl Sum for Content {
}
/// Builds a document or a flow node from content.
-struct Builder<'a, 'ctx> {
+struct Builder<'a, 'w> {
/// The core context.
- ctx: &'ctx mut Context,
+ world: &'w dyn World,
/// Scratch arenas for building.
scratch: &'a Scratch<'a>,
/// The current document building state.
@@ -354,10 +354,10 @@ struct Scratch<'a> {
templates: Arena<Content>,
}
-impl<'a, 'ctx> Builder<'a, 'ctx> {
- fn new(ctx: &'ctx mut Context, scratch: &'a Scratch<'a>, top: bool) -> Self {
+impl<'a, 'w> Builder<'a, 'w> {
+ fn new(world: &'w dyn World, scratch: &'a Scratch<'a>, top: bool) -> Self {
Self {
- ctx,
+ world,
scratch,
doc: top.then(|| DocBuilder::default()),
flow: FlowBuilder::default(),
@@ -388,7 +388,7 @@ impl<'a, 'ctx> Builder<'a, 'ctx> {
match content {
Content::Empty => return Ok(()),
Content::Text(text) => {
- if let Some(realized) = styles.apply(self.ctx, Target::Text(text))? {
+ if let Some(realized) = styles.apply(self.world, Target::Text(text))? {
let stored = self.scratch.templates.alloc(realized);
return self.accept(stored, styles);
}
@@ -431,7 +431,7 @@ impl<'a, 'ctx> Builder<'a, 'ctx> {
}
fn show(&mut self, node: &ShowNode, styles: StyleChain<'a>) -> TypResult<()> {
- if let Some(mut realized) = styles.apply(self.ctx, Target::Node(node))? {
+ if let Some(mut realized) = styles.apply(self.world, Target::Node(node))? {
let mut map = StyleMap::new();
let barrier = Barrier::new(node.id());
map.push(StyleEntry::Barrier(barrier));
diff --git a/src/model/layout.rs b/src/model/layout.rs
index d712a178..911cb4d5 100644
--- a/src/model/layout.rs
+++ b/src/model/layout.rs
@@ -15,7 +15,7 @@ use crate::geom::{
use crate::library::graphics::MoveNode;
use crate::library::layout::{AlignNode, PadNode};
use crate::util::Prehashed;
-use crate::Context;
+use crate::World;
/// A node that can be layouted into a sequence of regions.
///
@@ -24,7 +24,7 @@ pub trait Layout: 'static {
/// Layout this node into the given regions, producing frames.
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>>;
@@ -216,14 +216,14 @@ impl LayoutNode {
impl Layout for LayoutNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
let barrier = StyleEntry::Barrier(Barrier::new(self.id()));
let styles = barrier.chain(&styles);
- let mut frames = self.0.layout(ctx, regions, styles)?;
+ let mut frames = self.0.layout(world, regions, styles)?;
if let Some(role) = styles.role() {
for frame in &mut frames {
frame.apply_role(role);
@@ -285,7 +285,7 @@ struct EmptyNode;
impl Layout for EmptyNode {
fn layout(
&self,
- _: &mut Context,
+ _: &dyn World,
regions: &Regions,
_: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -307,7 +307,7 @@ struct SizedNode {
impl Layout for SizedNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
@@ -331,7 +331,7 @@ impl Layout for SizedNode {
};
// Layout the child.
- let mut frames = self.child.layout(ctx, &pod, styles)?;
+ let mut frames = self.child.layout(world, &pod, styles)?;
// Ensure frame size matches regions size if expansion is on.
let frame = &mut frames[0];
@@ -354,11 +354,11 @@ struct FillNode {
impl Layout for FillNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
- let mut frames = self.child.layout(ctx, regions, styles)?;
+ let mut frames = self.child.layout(world, regions, styles)?;
for frame in &mut frames {
let shape = Geometry::Rect(frame.size()).filled(self.fill);
frame.prepend(Point::zero(), Element::Shape(shape));
@@ -379,11 +379,11 @@ struct StrokeNode {
impl Layout for StrokeNode {
fn layout(
&self,
- ctx: &mut Context,
+ world: &dyn World,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
- let mut frames = self.child.layout(ctx, regions, styles)?;
+ let mut frames = self.child.layout(world, regions, styles)?;
for frame in &mut frames {
let shape = Geometry::Rect(frame.size()).stroked(self.stroke);
frame.prepend(Point::zero(), Element::Shape(shape));
diff --git a/src/model/recipe.rs b/src/model/recipe.rs
index 6261e704..f5ca2cb9 100644
--- a/src/model/recipe.rs
+++ b/src/model/recipe.rs
@@ -5,7 +5,7 @@ use crate::diag::TypResult;
use crate::eval::{Args, Func, Regex, Value};
use crate::library::structure::{EnumNode, ListNode};
use crate::syntax::Spanned;
-use crate::Context;
+use crate::World;
/// A show rule recipe.
#[derive(Clone, PartialEq, Hash)]
@@ -29,7 +29,7 @@ impl Recipe {
/// Try to apply the recipe to the target.
pub fn apply(
&self,
- ctx: &mut Context,
+ world: &dyn World,
styles: StyleChain,
sel: Selector,
target: Target,
@@ -37,7 +37,7 @@ impl Recipe {
let content = match (target, &self.pattern) {
(Target::Node(node), &Pattern::Node(id)) if node.id() == id => {
let node = node.unguard(sel);
- self.call(ctx, || {
+ self.call(world, || {
let dict = node.encode(styles);
Value::Content(Content::Show(node, Some(dict)))
})?
@@ -53,7 +53,7 @@ impl Recipe {
result.push(Content::Text(text[cursor .. start].into()));
}
- result.push(self.call(ctx, || Value::Str(mat.as_str().into()))?);
+ result.push(self.call(world, || Value::Str(mat.as_str().into()))?);
cursor = mat.end();
}
@@ -75,7 +75,7 @@ impl Recipe {
}
/// Call the recipe function, with the argument if desired.
- fn call<F>(&self, ctx: &mut Context, arg: F) -> TypResult<Content>
+ fn call<F>(&self, world: &dyn World, arg: F) -> TypResult<Content>
where
F: FnOnce() -> Value,
{
@@ -85,7 +85,7 @@ impl Recipe {
Args::new(self.func.span, [arg()])
};
- Ok(self.func.v.call_detached(ctx, args)?.display())
+ Ok(self.func.v.call_detached(world, args)?.display())
}
/// What kind of structure the property interrupts.
diff --git a/src/model/show.rs b/src/model/show.rs
index ac73cb76..e8d27977 100644
--- a/src/model/show.rs
+++ b/src/model/show.rs
@@ -6,7 +6,7 @@ use super::{Content, NodeId, Selector, StyleChain};
use crate::diag::TypResult;
use crate::eval::Dict;
use crate::util::Prehashed;
-use crate::Context;
+use crate::World;
/// A node that can be realized given some styles.
pub trait Show: 'static {
@@ -18,7 +18,7 @@ pub trait Show: 'static {
/// The base recipe for this node that is executed if there is no
/// user-defined show rule.
- fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content>;
+ fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content>;
/// Finalize this node given the realization of a base or user recipe. Use
/// this for effects that should work even in the face of a user-defined
@@ -30,7 +30,7 @@ pub trait Show: 'static {
#[allow(unused_variables)]
fn finalize(
&self,
- ctx: &mut Context,
+ world: &dyn World,
styles: StyleChain,
realized: Content,
) -> TypResult<Content> {
@@ -74,17 +74,17 @@ impl Show for ShowNode {
self.0.encode(styles)
}
- fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
- self.0.realize(ctx, styles)
+ fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> {
+ self.0.realize(world, styles)
}
fn finalize(
&self,
- ctx: &mut Context,
+ world: &dyn World,
styles: StyleChain,
realized: Content,
) -> TypResult<Content> {
- self.0.finalize(ctx, styles, realized)
+ self.0.finalize(world, styles, realized)
}
fn pack(self) -> ShowNode {
diff --git a/src/model/styles.rs b/src/model/styles.rs
index eab33402..53ef926c 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -8,7 +8,7 @@ use crate::diag::TypResult;
use crate::frame::Role;
use crate::library::text::{FontFamily, TextNode};
use crate::util::ReadableTypeId;
-use crate::Context;
+use crate::World;
/// A map of style properties.
#[derive(Default, Clone, PartialEq, Hash)]
@@ -277,7 +277,7 @@ impl<'a> StyleChain<'a> {
}
/// Apply show recipes in this style chain to a target.
- pub fn apply(self, ctx: &mut Context, target: Target) -> TypResult<Option<Content>> {
+ pub fn apply(self, world: &dyn World, target: Target) -> TypResult<Option<Content>> {
// Find out how many recipes there any and whether any of their patterns
// match.
let mut n = 0;
@@ -296,7 +296,9 @@ impl<'a> StyleChain<'a> {
let sel = Selector::Nth(n);
if self.guarded(sel) {
guarded = true;
- } else if let Some(content) = recipe.apply(ctx, self, sel, target)? {
+ } else if let Some(content) =
+ recipe.apply(world, self, sel, target)?
+ {
realized = Some(content);
break;
}
@@ -312,7 +314,7 @@ impl<'a> StyleChain<'a> {
if self.guarded(sel) {
guarded = true;
} else {
- let content = node.unguard(sel).realize(ctx, self)?;
+ let content = node.unguard(sel).realize(world, self)?;
realized = Some(content.styled_with_entry(StyleEntry::Guard(sel)));
}
}
@@ -320,7 +322,7 @@ impl<'a> StyleChain<'a> {
// Finalize only if guarding didn't stop any recipe.
if !guarded {
if let Some(content) = realized {
- realized = Some(node.finalize(ctx, self, content)?);
+ realized = Some(node.finalize(world, self, content)?);
}
}
}
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index 60f780b4..9272dcfc 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -15,21 +15,21 @@ use super::{
/// Returns the range in the new source that was ultimately reparsed.
pub fn reparse(
root: &mut SyntaxNode,
- src: &str,
+ text: &str,
replaced: Range<usize>,
replacement_len: usize,
) -> Range<usize> {
if let SyntaxNode::Inner(inner) = root {
- let change = Change { src, replaced, replacement_len };
+ let change = Change { text, replaced, replacement_len };
if let Some(range) = try_reparse(&change, Arc::make_mut(inner), 0, true, true) {
return range;
}
}
let id = root.span().source();
- *root = parse(src);
+ *root = parse(text);
root.numberize(id, Span::FULL).unwrap();
- 0 .. src.len()
+ 0 .. text.len()
}
/// Try to reparse inside the given node.
@@ -228,27 +228,27 @@ fn replace(
let newborn_span = superseded_span.start .. newborn_end;
let mut prefix = "";
- for (i, c) in change.src[.. newborn_span.start].char_indices().rev() {
+ for (i, c) in change.text[.. newborn_span.start].char_indices().rev() {
if is_newline(c) {
break;
}
- prefix = &change.src[i .. newborn_span.start];
+ prefix = &change.text[i .. newborn_span.start];
}
let (newborns, terminated, amount) = match mode {
ReparseMode::Code => reparse_code_block(
&prefix,
- &change.src[newborn_span.start ..],
+ &change.text[newborn_span.start ..],
newborn_span.len(),
),
ReparseMode::Content => reparse_content_block(
&prefix,
- &change.src[newborn_span.start ..],
+ &change.text[newborn_span.start ..],
newborn_span.len(),
),
ReparseMode::MarkupElements { at_start, min_indent } => reparse_markup_elements(
&prefix,
- &change.src[newborn_span.start ..],
+ &change.text[newborn_span.start ..],
newborn_span.len(),
differential,
&node.children().as_slice()[superseded_start ..],
@@ -272,7 +272,7 @@ fn replace(
/// A description of a change.
struct Change<'a> {
/// The new source code, with the change applied.
- src: &'a str,
+ text: &'a str,
/// Which range in the old source file was changed.
replaced: Range<usize>,
/// How many characters replaced the text in `replaced`.
@@ -396,7 +396,7 @@ mod tests {
fn test(prev: &str, range: Range<usize>, with: &str, goal: Range<usize>) {
let mut source = Source::detached(prev);
let range = source.edit(range, with);
- check(source.src(), source.root(), &parse(source.src()));
+ check(source.text(), source.root(), &parse(source.text()));
assert_eq!(range, goal);
}
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 0737d4ca..a8dee7f3 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -16,15 +16,15 @@ use crate::syntax::{NodeKind, SpanPos, SyntaxNode};
use crate::util::EcoString;
/// Parse a source file.
-pub fn parse(src: &str) -> SyntaxNode {
- let mut p = Parser::new(src, TokenMode::Markup);
+pub fn parse(text: &str) -> SyntaxNode {
+ let mut p = Parser::new(text, TokenMode::Markup);
markup(&mut p, true);
p.finish().into_iter().next().unwrap()
}
/// Parse code directly, only used for syntax highlighting.
-pub fn parse_code(src: &str) -> Vec<SyntaxNode> {
- let mut p = Parser::new(src, TokenMode::Code);
+pub fn parse_code(text: &str) -> Vec<SyntaxNode> {
+ let mut p = Parser::new(text, TokenMode::Code);
code(&mut p);
p.finish()
}
@@ -34,10 +34,10 @@ pub fn parse_code(src: &str) -> Vec<SyntaxNode> {
/// Returns `Some` if all of the input was consumed.
fn reparse_code_block(
prefix: &str,
- src: &str,
+ text: &str,
end_pos: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
- let mut p = Parser::with_prefix(prefix, src, TokenMode::Code);
+ let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
if !p.at(NodeKind::LeftBrace) {
return None;
}
@@ -58,10 +58,10 @@ fn reparse_code_block(
/// Returns `Some` if all of the input was consumed.
fn reparse_content_block(
prefix: &str,
- src: &str,
+ text: &str,
end_pos: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
- let mut p = Parser::with_prefix(prefix, src, TokenMode::Code);
+ let mut p = Parser::with_prefix(prefix, text, TokenMode::Code);
if !p.at(NodeKind::LeftBracket) {
return None;
}
@@ -82,14 +82,14 @@ fn reparse_content_block(
/// Returns `Some` if all of the input was consumed.
fn reparse_markup_elements(
prefix: &str,
- src: &str,
+ text: &str,
end_pos: usize,
differential: isize,
reference: &[SyntaxNode],
mut at_start: bool,
min_indent: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
- let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup);
+ let mut p = Parser::with_prefix(prefix, text, TokenMode::Markup);
let mut node: Option<&SyntaxNode> = None;
let mut iter = reference.iter();
@@ -996,12 +996,12 @@ mod tests {
use std::fmt::Debug;
#[track_caller]
- pub fn check<T>(src: &str, found: T, expected: T)
+ pub fn check<T>(text: &str, found: T, expected: T)
where
T: Debug + PartialEq,
{
if found != expected {
- println!("source: {src:?}");
+ println!("source: {text:?}");
println!("expected: {expected:#?}");
println!("found: {found:#?}");
panic!("test failed");
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 685f1e69..90b6e610 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -30,15 +30,15 @@ pub struct Parser<'s> {
impl<'s> Parser<'s> {
/// Create a new parser for the source string.
- pub fn new(src: &'s str, mode: TokenMode) -> Self {
- Self::with_prefix("", src, mode)
+ pub fn new(text: &'s str, mode: TokenMode) -> Self {
+ Self::with_prefix("", text, mode)
}
/// Create a new parser for the source string that is prefixed by some text
/// that does not need to be parsed but taken into account for column
/// calculation.
- pub fn with_prefix(prefix: &str, src: &'s str, mode: TokenMode) -> Self {
- let mut tokens = Tokens::with_prefix(prefix, src, mode);
+ pub fn with_prefix(prefix: &str, text: &'s str, mode: TokenMode) -> Self {
+ let mut tokens = Tokens::with_prefix(prefix, text, mode);
let current = tokens.next();
Self {
tokens,
diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs
index 6fab9f21..bce2da3c 100644
--- a/src/parse/resolve.rs
+++ b/src/parse/resolve.rs
@@ -23,7 +23,7 @@ pub fn resolve_string(string: &str) -> EcoString {
Some('r') => out.push('\r'),
Some('t') => out.push('\t'),
Some('u') if s.eat_if('{') => {
- // TODO: Feedback if closing brace is missing.
+ // TODO: Error if closing brace is missing.
let sequence = s.eat_while(char::is_ascii_hexdigit);
let _terminated = s.eat_if('}');
@@ -33,7 +33,7 @@ pub fn resolve_string(string: &str) -> EcoString {
}
}
- // TODO: Feedback about invalid escape sequence.
+ // TODO: Error for invalid escape sequence.
_ => out.push_str(s.from(start)),
}
}
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index 67d413fd..84a63ba1 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -34,16 +34,16 @@ pub enum TokenMode {
impl<'s> Tokens<'s> {
/// Create a new token iterator with the given mode.
#[inline]
- pub fn new(src: &'s str, mode: TokenMode) -> Self {
- Self::with_prefix("", src, mode)
+ pub fn new(text: &'s str, mode: TokenMode) -> Self {
+ Self::with_prefix("", text, mode)
}
/// Create a new token iterator with the given mode and a prefix to offset
/// column calculations.
#[inline]
- pub fn with_prefix(prefix: &str, src: &'s str, mode: TokenMode) -> Self {
+ pub fn with_prefix(prefix: &str, text: &'s str, mode: TokenMode) -> Self {
Self {
- s: Scanner::new(src),
+ s: Scanner::new(text),
mode,
terminated: true,
column_offset: column(prefix, prefix.len(), 0),
@@ -770,9 +770,9 @@ mod tests {
t!(Markup $($tts)*);
t!(Code $($tts)*);
};
- ($mode:ident $([$blocks:literal])?: $src:expr => $($token:expr),*) => {{
+ ($mode:ident $([$blocks:literal])?: $text:expr => $($token:expr),*) => {{
// Test without suffix.
- t!(@$mode: $src => $($token),*);
+ t!(@$mode: $text => $($token),*);
// Suffixes described by four-tuples of:
//
@@ -810,21 +810,21 @@ mod tests {
// Test with each applicable suffix.
for &(block, mode, suffix, ref token) in suffixes {
- let src = $src;
+ let text = $text;
#[allow(unused_variables)]
let blocks = BLOCKS;
$(let blocks = $blocks;)?
assert!(!blocks.contains(|c| !BLOCKS.contains(c)));
if (mode.is_none() || mode == Some($mode)) && blocks.contains(block) {
- t!(@$mode: format!("{}{}", src, suffix) => $($token,)* token);
+ t!(@$mode: format!("{}{}", text, suffix) => $($token,)* token);
}
}
}};
- (@$mode:ident: $src:expr => $($token:expr),*) => {{
- let src = $src;
- let found = Tokens::new(&src, $mode).collect::<Vec<_>>();
+ (@$mode:ident: $text:expr => $($token:expr),*) => {{
+ let text = $text;
+ let found = Tokens::new(&text, $mode).collect::<Vec<_>>();
let expected = vec![$($token.clone()),*];
- check(&src, found, expected);
+ check(&text, found, expected);
}};
}
diff --git a/src/source.rs b/src/source.rs
index 24d830ad..c3648e11 100644
--- a/src/source.rs
+++ b/src/source.rs
@@ -1,158 +1,16 @@
//! Source file management.
-use std::collections::HashMap;
-use std::io;
use std::ops::Range;
use std::path::{Path, PathBuf};
-use std::sync::Arc;
use unscanny::Scanner;
-use crate::diag::{failed_to_load, StrResult, TypResult};
-use crate::loading::{FileHash, Loader};
+use crate::diag::TypResult;
use crate::parse::{is_newline, parse, reparse};
use crate::syntax::ast::Markup;
use crate::syntax::{Span, SyntaxNode};
use crate::util::{PathExt, StrExt};
-#[cfg(feature = "codespan-reporting")]
-use codespan_reporting::files::{self, Files};
-
-/// A unique identifier for a loaded source file.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct SourceId(u16);
-
-impl SourceId {
- /// Create a new source id for a file that is not part of a store.
- pub const fn detached() -> Self {
- Self(u16::MAX)
- }
-
- /// Create a source id from the raw underlying value.
- ///
- /// This should only be called with values returned by
- /// [`into_raw`](Self::into_raw).
- pub const fn from_raw(v: u16) -> Self {
- Self(v)
- }
-
- /// Convert into the raw underlying value.
- pub const fn into_raw(self) -> u16 {
- self.0
- }
-}
-
-/// Storage for loaded source files.
-pub struct SourceStore {
- loader: Arc<dyn Loader>,
- files: HashMap<FileHash, SourceId>,
- sources: Vec<Source>,
-}
-
-impl SourceStore {
- /// Create a new, empty source store.
- pub fn new(loader: Arc<dyn Loader>) -> Self {
- Self {
- loader,
- files: HashMap::new(),
- sources: vec![],
- }
- }
-
- /// Get a reference to a loaded source file.
- ///
- /// This panics if no source file with this `id` exists. This function
- /// should only be called with ids returned by this store's
- /// [`load()`](Self::load) and [`provide()`](Self::provide) methods.
- #[track_caller]
- pub fn get(&self, id: SourceId) -> &Source {
- &self.sources[id.0 as usize]
- }
-
- /// Load a source file from a path relative to the compilation environment's
- /// root.
- ///
- /// If there already exists a source file for this path, it is
- /// [replaced](Source::replace).
- pub fn load(&mut self, path: &Path) -> StrResult<SourceId> {
- let mut try_load = || -> io::Result<SourceId> {
- let hash = self.loader.resolve(path)?;
- if let Some(&id) = self.files.get(&hash) {
- return Ok(id);
- }
-
- let data = self.loader.file(path)?;
- let src = String::from_utf8(data.to_vec()).map_err(|_| {
- io::Error::new(io::ErrorKind::InvalidData, "file is not valid utf-8")
- })?;
-
- Ok(self.provide(path, src))
- };
-
- try_load().map_err(|err| failed_to_load("source file", path, err))
- }
-
- /// Directly provide a source file.
- ///
- /// The `path` does not need to be [resolvable](Loader::resolve) through the
- /// `loader`. If it is though, imports that resolve to the same file hash
- /// will use the inserted file instead of going through [`Loader::file`].
- ///
- /// If the path is resolvable and points to an existing source file, it is
- /// [replaced](Source::replace).
- pub fn provide(&mut self, path: impl AsRef<Path>, src: String) -> SourceId {
- let path = path.as_ref();
- let hash = self.loader.resolve(path).ok();
-
- // Check for existing file and replace if one exists.
- if let Some(&id) = hash.and_then(|hash| self.files.get(&hash)) {
- self.replace(id, src);
- return id;
- }
-
- // No existing file yet, so we allocate a new id.
- let id = SourceId(self.sources.len() as u16);
- self.sources.push(Source::new(id, path, src));
-
- // Register in file map if the path was known to the loader.
- if let Some(hash) = hash {
- self.files.insert(hash, id);
- }
-
- id
- }
-
- /// Fully [replace](Source::replace) the source text of a file.
- ///
- /// This panics if no source file with this `id` exists.
- #[track_caller]
- pub fn replace(&mut self, id: SourceId, src: String) {
- self.sources[id.0 as usize].replace(src)
- }
-
- /// [Edit](Source::edit) a source file by replacing the given range.
- ///
- /// This panics if no source file with this `id` exists or if the `replace`
- /// range is out of bounds.
- #[track_caller]
- pub fn edit(
- &mut self,
- id: SourceId,
- replace: Range<usize>,
- with: &str,
- ) -> Range<usize> {
- self.sources[id.0 as usize].edit(replace, with)
- }
-
- /// Map a span that points into a [file](Source::range) stored in this
- /// source store to a byte range.
- ///
- /// Panics if the span does not point into this source store.
- pub fn range(&self, span: Span) -> Range<usize> {
- self.get(span.source()).range(span)
- }
-}
-
/// A single source file.
///
/// _Note_: All line and column indices start at zero, just like byte indices.
@@ -160,7 +18,7 @@ impl SourceStore {
pub struct Source {
id: SourceId,
path: PathBuf,
- src: String,
+ text: String,
lines: Vec<Line>,
root: SyntaxNode,
rev: usize,
@@ -168,32 +26,32 @@ pub struct Source {
impl Source {
/// Create a new source file.
- pub fn new(id: SourceId, path: &Path, src: String) -> Self {
+ pub fn new(id: SourceId, path: &Path, text: String) -> Self {
let lines = std::iter::once(Line { byte_idx: 0, utf16_idx: 0 })
- .chain(lines(0, 0, &src))
+ .chain(lines(0, 0, &text))
.collect();
- let mut root = parse(&src);
+ let mut root = parse(&text);
root.numberize(id, Span::FULL).unwrap();
Self {
id,
path: path.normalize(),
root,
- src,
+ text,
lines,
rev: 0,
}
}
/// Create a source file without a real id and path, usually for testing.
- pub fn detached(src: impl Into<String>) -> Self {
- Self::new(SourceId::detached(), Path::new(""), src.into())
+ pub fn detached(text: impl Into<String>) -> Self {
+ Self::new(SourceId::detached(), Path::new(""), text.into())
}
/// Create a source file with the same synthetic span for all nodes.
- pub fn synthesized(src: impl Into<String>, span: Span) -> Self {
- let mut file = Self::detached(src);
+ pub fn synthesized(text: impl Into<String>, span: Span) -> Self {
+ let mut file = Self::detached(text);
file.root.synthesize(span);
file.id = span.source();
file
@@ -225,8 +83,8 @@ impl Source {
}
/// The whole source as a string slice.
- pub fn src(&self) -> &str {
- &self.src
+ pub fn text(&self) -> &str {
+ &self.text
}
/// The revision number of the file.
@@ -239,15 +97,15 @@ impl Source {
/// Slice out the part of the source code enclosed by the range.
pub fn get(&self, range: Range<usize>) -> Option<&str> {
- self.src.get(range)
+ self.text.get(range)
}
/// Fully replace the source text and increase the revision number.
- pub fn replace(&mut self, src: String) {
- self.src = src;
+ pub fn replace(&mut self, text: String) {
+ self.text = text;
self.lines = vec![Line { byte_idx: 0, utf16_idx: 0 }];
- self.lines.extend(lines(0, 0, &self.src));
- self.root = parse(&self.src);
+ self.lines.extend(lines(0, 0, &self.text));
+ self.root = parse(&self.text);
self.root.numberize(self.id(), Span::FULL).unwrap();
self.rev = self.rev.wrapping_add(1);
}
@@ -263,34 +121,34 @@ impl Source {
let start_byte = replace.start;
let start_utf16 = self.byte_to_utf16(replace.start).unwrap();
- self.src.replace_range(replace.clone(), with);
+ self.text.replace_range(replace.clone(), with);
// Remove invalidated line starts.
let line = self.byte_to_line(start_byte).unwrap();
self.lines.truncate(line + 1);
// Handle adjoining of \r and \n.
- if self.src[.. start_byte].ends_with('\r') && with.starts_with('\n') {
+ if self.text[.. start_byte].ends_with('\r') && with.starts_with('\n') {
self.lines.pop();
}
// Recalculate the line starts after the edit.
self.lines
- .extend(lines(start_byte, start_utf16, &self.src[start_byte ..]));
+ .extend(lines(start_byte, start_utf16, &self.text[start_byte ..]));
// Incrementally reparse the replaced range.
- reparse(&mut self.root, &self.src, replace, with.len())
+ reparse(&mut self.root, &self.text, replace, with.len())
}
/// Get the length of the file in UTF-8 encoded bytes.
pub fn len_bytes(&self) -> usize {
- self.src.len()
+ self.text.len()
}
/// Get the length of the file in UTF-16 code units.
pub fn len_utf16(&self) -> usize {
let last = self.lines.last().unwrap();
- last.utf16_idx + self.src[last.byte_idx ..].len_utf16()
+ last.utf16_idx + self.text[last.byte_idx ..].len_utf16()
}
/// Get the length of the file in lines.
@@ -311,13 +169,13 @@ impl Source {
pub fn byte_to_utf16(&self, byte_idx: usize) -> Option<usize> {
let line_idx = self.byte_to_line(byte_idx)?;
let line = self.lines.get(line_idx)?;
- let head = self.src.get(line.byte_idx .. byte_idx)?;
+ let head = self.text.get(line.byte_idx .. byte_idx)?;
Some(line.utf16_idx + head.len_utf16())
}
/// Return the index of the line that contains the given byte index.
pub fn byte_to_line(&self, byte_idx: usize) -> Option<usize> {
- (byte_idx <= self.src.len()).then(|| {
+ (byte_idx <= self.text.len()).then(|| {
match self.lines.binary_search_by_key(&byte_idx, |line| line.byte_idx) {
Ok(i) => i,
Err(i) => i - 1,
@@ -346,14 +204,14 @@ impl Source {
)?;
let mut k = line.utf16_idx;
- for (i, c) in self.src[line.byte_idx ..].char_indices() {
+ for (i, c) in self.text[line.byte_idx ..].char_indices() {
if k >= utf16_idx {
return Some(line.byte_idx + i);
}
k += c.len_utf16();
}
- (k == utf16_idx).then(|| self.src.len())
+ (k == utf16_idx).then(|| self.text.len())
}
@@ -365,7 +223,7 @@ impl Source {
/// Return the range which encloses the given line.
pub fn line_to_range(&self, line_idx: usize) -> Option<Range<usize>> {
let start = self.line_to_byte(line_idx)?;
- let end = self.line_to_byte(line_idx + 1).unwrap_or(self.src.len());
+ let end = self.line_to_byte(line_idx + 1).unwrap_or(self.text.len());
Some(start .. end)
}
@@ -388,6 +246,30 @@ impl Source {
}
}
+/// A unique identifier for a loaded source file.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct SourceId(u16);
+
+impl SourceId {
+ /// Create a new source id for a file that is not part of a store.
+ pub const fn detached() -> Self {
+ Self(u16::MAX)
+ }
+
+ /// Create a source id from the raw underlying value.
+ ///
+ /// This should only be called with values returned by
+ /// [`into_raw`](Self::into_raw).
+ pub const fn from_raw(v: u16) -> Self {
+ Self(v)
+ }
+
+ /// Convert into the raw underlying value.
+ pub const fn into_raw(self) -> u16 {
+ self.0
+ }
+}
+
/// Metadata about a line.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Line {
@@ -401,9 +283,9 @@ struct Line {
fn lines(
byte_offset: usize,
utf16_offset: usize,
- string: &str,
+ text: &str,
) -> impl Iterator<Item = Line> + '_ {
- let mut s = Scanner::new(string);
+ let mut s = Scanner::new(text);
let mut utf16_idx = utf16_offset;
std::iter::from_fn(move || {
@@ -427,56 +309,6 @@ fn lines(
})
}
-#[cfg(feature = "codespan-reporting")]
-impl<'a> Files<'a> for SourceStore {
- type FileId = SourceId;
- type Name = std::path::Display<'a>;
- type Source = &'a str;
-
- fn name(&'a self, id: SourceId) -> Result<Self::Name, files::Error> {
- Ok(self.get(id).path().display())
- }
-
- fn source(&'a self, id: SourceId) -> Result<Self::Source, files::Error> {
- Ok(self.get(id).src())
- }
-
- fn line_index(&'a self, id: SourceId, given: usize) -> Result<usize, files::Error> {
- let source = self.get(id);
- source
- .byte_to_line(given)
- .ok_or_else(|| files::Error::IndexTooLarge { given, max: source.len_bytes() })
- }
-
- fn line_range(
- &'a self,
- id: SourceId,
- given: usize,
- ) -> Result<std::ops::Range<usize>, files::Error> {
- let source = self.get(id);
- source
- .line_to_range(given)
- .ok_or_else(|| files::Error::LineTooLarge { given, max: source.len_lines() })
- }
-
- fn column_number(
- &'a self,
- id: SourceId,
- _: usize,
- given: usize,
- ) -> Result<usize, files::Error> {
- let source = self.get(id);
- source.byte_to_column(given).ok_or_else(|| {
- let max = source.len_bytes();
- if given <= max {
- files::Error::InvalidCharBoundary { given }
- } else {
- files::Error::IndexTooLarge { given, max }
- }
- })
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -563,7 +395,7 @@ mod tests {
let mut source = Source::detached(prev);
let result = Source::detached(after);
source.edit(range, with);
- assert_eq!(source.src, result.src);
+ assert_eq!(source.text, result.text);
assert_eq!(source.root, result.root);
assert_eq!(source.lines, result.lines);
}
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 6470e4fb..7f5ee083 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -384,10 +384,10 @@ mod tests {
use Category::*;
#[track_caller]
- fn test(src: &str, goal: &[(Range<usize>, Category)]) {
+ fn test(text: &str, goal: &[(Range<usize>, Category)]) {
let mut vec = vec![];
- let source = Source::detached(src);
- let full = 0 .. src.len();
+ let source = Source::detached(text);
+ let full = 0 .. text.len();
highlight_node(source.root(), full, &mut |range, category| {
vec.push((range, category));
});
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index eb070a04..c2b06efe 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -980,7 +980,7 @@ impl NodeKind {
Self::LineComment => "line comment",
Self::BlockComment => "block comment",
Self::Error(_, _) => "parse error",
- Self::Unknown(src) => match src.as_str() {
+ Self::Unknown(text) => match text.as_str() {
"*/" => "end of block comment",
_ => "invalid token",
},
@@ -1107,7 +1107,7 @@ impl Hash for NodeKind {
Self::LineComment => {}
Self::BlockComment => {}
Self::Error(pos, msg) => (pos, msg).hash(state),
- Self::Unknown(src) => src.hash(state),
+ Self::Unknown(text) => text.hash(state),
}
}
}
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index 3f66efa7..4eae4124 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -42,8 +42,8 @@ impl<T: Debug> Debug for Spanned<T> {
/// A unique identifier for a syntax node.
///
/// This is used throughout the compiler to track which source section an error
-/// or element stems from. Can be [mapped back](crate::source::SourceStore::range)
-/// to a source id + byte range for user facing display.
+/// or element stems from. Can be [mapped back](crate::source::Source::range)
+/// to a byte range for user facing display.
///
/// Span ids are ordered in the tree to enable quickly finding the node with
/// some id:
diff --git a/src/util/buffer.rs b/src/util/buffer.rs
new file mode 100644
index 00000000..daee86f9
--- /dev/null
+++ b/src/util/buffer.rs
@@ -0,0 +1,59 @@
+use std::fmt::{self, Debug, Formatter};
+use std::ops::Deref;
+use std::sync::Arc;
+
+use super::Prehashed;
+
+/// A shared buffer that is cheap to clone and hash.
+#[derive(Clone, Hash, Eq, PartialEq)]
+pub struct Buffer(Prehashed<Arc<Vec<u8>>>);
+
+impl Buffer {
+ /// Return a view into the buffer.
+ pub fn as_slice(&self) -> &[u8] {
+ self
+ }
+
+ /// Return a copy of the buffer as a vector.
+ pub fn to_vec(&self) -> Vec<u8> {
+ self.0.to_vec()
+ }
+}
+
+impl From<&[u8]> for Buffer {
+ fn from(slice: &[u8]) -> Self {
+ Self(Prehashed::new(Arc::new(slice.to_vec())))
+ }
+}
+
+impl From<Vec<u8>> for Buffer {
+ fn from(vec: Vec<u8>) -> Self {
+ Self(Prehashed::new(Arc::new(vec)))
+ }
+}
+
+impl From<Arc<Vec<u8>>> for Buffer {
+ fn from(arc: Arc<Vec<u8>>) -> Self {
+ Self(Prehashed::new(arc))
+ }
+}
+
+impl Deref for Buffer {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl AsRef<[u8]> for Buffer {
+ fn as_ref(&self) -> &[u8] {
+ self
+ }
+}
+
+impl Debug for Buffer {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.pad("Buffer(..)")
+ }
+}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index e0ba312f..4a48b1d3 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -2,8 +2,10 @@
#[macro_use]
mod eco;
+mod buffer;
mod hash;
+pub use buffer::Buffer;
pub use eco::EcoString;
pub use hash::Prehashed;