summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-02-17 17:25:57 +0100
committerLaurenz <laurmaedje@gmail.com>2022-02-17 17:41:45 +0100
commit35610a8c6a1721010b933324dacfe2c4d58761a3 (patch)
tree2d02a53f541b7ebc48ace29dacedf534b670c6c1
parentc5e67af22bd6242366819879be84c10c4dd135be (diff)
Fallible layout
-rw-r--r--src/eval/show.rs8
-rw-r--r--src/eval/template.rs36
-rw-r--r--src/layout/mod.rs33
-rw-r--r--src/lib.rs4
-rw-r--r--src/library/align.rs6
-rw-r--r--src/library/columns.rs6
-rw-r--r--src/library/deco.rs6
-rw-r--r--src/library/flow.rs21
-rw-r--r--src/library/grid.rs74
-rw-r--r--src/library/heading.rs6
-rw-r--r--src/library/hide.rs6
-rw-r--r--src/library/image.rs4
-rw-r--r--src/library/link.rs4
-rw-r--r--src/library/list.rs6
-rw-r--r--src/library/math.rs4
-rw-r--r--src/library/pad.rs6
-rw-r--r--src/library/page.rs8
-rw-r--r--src/library/par.rs12
-rw-r--r--src/library/place.rs6
-rw-r--r--src/library/raw.rs4
-rw-r--r--src/library/shape.rs8
-rw-r--r--src/library/stack.rs17
-rw-r--r--src/library/table.rs6
-rw-r--r--src/library/text.rs8
-rw-r--r--src/library/transform.rs6
-rw-r--r--tests/typeset.rs9
26 files changed, 174 insertions, 140 deletions
diff --git a/src/eval/show.rs b/src/eval/show.rs
index 6157485d..a6a48e6f 100644
--- a/src/eval/show.rs
+++ b/src/eval/show.rs
@@ -4,12 +4,14 @@ use std::hash::{Hash, Hasher};
use std::sync::Arc;
use super::{StyleChain, Template};
+use crate::diag::TypResult;
use crate::util::Prehashed;
+use crate::Vm;
/// A node that can be realized given some styles.
pub trait Show {
/// Realize the template in the given styles.
- fn show(&self, styles: StyleChain) -> Template;
+ fn show(&self, vm: &mut Vm, styles: StyleChain) -> TypResult<Template>;
/// Convert to a packed show node.
fn pack(self) -> ShowNode
@@ -40,8 +42,8 @@ impl ShowNode {
}
impl Show for ShowNode {
- fn show(&self, styles: StyleChain) -> Template {
- self.0.show(styles)
+ fn show(&self, vm: &mut Vm, styles: StyleChain) -> TypResult<Template> {
+ self.0.show(vm, styles)
}
fn pack(self) -> ShowNode {
diff --git a/src/eval/template.rs b/src/eval/template.rs
index 2cd6797a..b1fe07fe 100644
--- a/src/eval/template.rs
+++ b/src/eval/template.rs
@@ -165,20 +165,22 @@ impl Template {
}
/// Layout this template into a collection of pages.
- pub fn layout(&self, vm: &mut Vm) -> Vec<Arc<Frame>> {
+ pub fn layout(&self, vm: &mut Vm) -> TypResult<Vec<Arc<Frame>>> {
let style_arena = Arena::new();
let template_arena = Arena::new();
let mut builder = Builder::new(&style_arena, &template_arena, true);
let chain = StyleChain::new(vm.styles);
- builder.process(self, chain);
+ builder.process(self, vm, chain)?;
builder.finish_page(true, false, chain);
+ let mut frames = vec![];
let (pages, shared) = builder.pages.unwrap().finish();
- pages
- .iter()
- .flat_map(|(page, map)| page.layout(vm, map.chain(&shared)))
- .collect()
+ for (page, map) in pages.iter() {
+ frames.extend(page.layout(vm, map.chain(&shared))?);
+ }
+
+ Ok(frames)
}
}
@@ -269,12 +271,12 @@ impl Layout for Template {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let style_arena = Arena::new();
let template_arena = Arena::new();
let mut builder = Builder::new(&style_arena, &template_arena, false);
- builder.process(self, styles);
+ builder.process(self, vm, styles)?;
builder.finish_par(styles);
let (flow, shared) = builder.flow.finish();
@@ -323,7 +325,12 @@ impl<'a> Builder<'a> {
}
/// Process a template.
- fn process(&mut self, template: &'a Template, styles: StyleChain<'a>) {
+ fn process(
+ &mut self,
+ template: &'a Template,
+ vm: &mut Vm,
+ styles: StyleChain<'a>,
+ ) -> TypResult<()> {
match template {
Template::Space => {
self.par.weak(ParChild::Text(' '.into()), 0, styles);
@@ -382,8 +389,9 @@ impl<'a> Builder<'a> {
}
}
Template::Show(node) => {
- let template = self.template_arena.alloc(node.show(styles));
- self.process(template, styles.unscoped(node.id()));
+ let template = node.show(vm, styles)?;
+ let stored = self.template_arena.alloc(template);
+ self.process(stored, vm, styles.unscoped(node.id()))?;
}
Template::Styled(styled) => {
let (sub, map) = styled.as_ref();
@@ -397,7 +405,7 @@ impl<'a> Builder<'a> {
None => {}
}
- self.process(sub, styles);
+ self.process(sub, vm, styles)?;
match interruption {
Some(Interruption::Page) => self.finish_page(true, false, styles),
@@ -407,10 +415,12 @@ impl<'a> Builder<'a> {
}
Template::Sequence(seq) => {
for sub in seq.iter() {
- self.process(sub, styles);
+ self.process(sub, vm, styles)?;
}
}
}
+
+ Ok(())
}
/// Finish the currently built paragraph.
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index d47e37bb..0d1836fd 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -15,6 +15,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
+use crate::diag::TypResult;
use crate::eval::StyleChain;
use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
use crate::geom::{Align, Linear, Paint, Point, Sides, Size, Spec, Transform};
@@ -33,7 +34,7 @@ pub trait Layout {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>>;
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>>;
/// Convert to a packed node.
fn pack(self) -> LayoutNode
@@ -137,7 +138,7 @@ impl Layout for LayoutNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let styles = styles.barred(self.id());
#[cfg(not(feature = "layout-cache"))]
@@ -155,10 +156,10 @@ impl Layout for LayoutNode {
// #[track_caller] annotation doesn't work.
#[cfg(feature = "layout-cache")]
if let Some(frames) = vm.layout_cache.get(hash, regions) {
- frames
+ Ok(frames)
} else {
vm.level += 1;
- let frames = self.0.layout(vm, regions, styles);
+ let frames = self.0.layout(vm, regions, styles)?;
vm.level -= 1;
let entry = FramesEntry::new(frames.clone(), vm.level);
@@ -175,7 +176,7 @@ impl Layout for LayoutNode {
}
vm.layout_cache.insert(hash, entry);
- frames
+ Ok(frames)
}
}
@@ -248,11 +249,11 @@ impl Layout for EmptyNode {
_: &mut Vm,
regions: &Regions,
_: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let size = regions.expand.select(regions.current, Size::zero());
let mut cts = Constraints::new(regions.expand);
cts.exact = regions.current.filter(regions.expand);
- vec![Frame::new(size).constrain(cts)]
+ Ok(vec![Frame::new(size).constrain(cts)])
}
}
@@ -271,7 +272,7 @@ impl Layout for SizedNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let is_auto = self.sizing.map_is_none();
let is_rel = self.sizing.map(|s| s.map_or(false, Linear::is_relative));
@@ -292,7 +293,7 @@ impl Layout for SizedNode {
Regions::one(size, base, expand)
};
- let mut frames = self.child.layout(vm, &pod, styles);
+ let mut frames = self.child.layout(vm, &pod, styles)?;
let Constrained { item: frame, cts } = &mut frames[0];
// Ensure frame size matches regions size if expansion is on.
@@ -306,7 +307,7 @@ impl Layout for SizedNode {
cts.exact = regions.current.filter(regions.expand | is_auto);
cts.base = regions.base.filter(is_rel | is_auto);
- frames
+ Ok(frames)
}
}
@@ -325,13 +326,13 @@ impl Layout for FillNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
- let mut frames = self.child.layout(vm, regions, styles);
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
+ let mut frames = self.child.layout(vm, regions, styles)?;
for Constrained { item: frame, .. } in &mut frames {
let shape = Shape::filled(Geometry::Rect(frame.size), self.fill);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
}
- frames
+ Ok(frames)
}
}
@@ -350,12 +351,12 @@ impl Layout for StrokeNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
- let mut frames = self.child.layout(vm, regions, styles);
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
+ let mut frames = self.child.layout(vm, regions, styles)?;
for Constrained { item: frame, .. } in &mut frames {
let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
}
- frames
+ Ok(frames)
}
}
diff --git a/src/lib.rs b/src/lib.rs
index d4a8fba5..46bcad8d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -283,9 +283,7 @@ impl<'a> Vm<'a> {
/// diagnostics in the form of a vector of error message with file and span
/// information.
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
- let module = self.evaluate(id)?;
- let frames = module.template.layout(self);
- Ok(frames)
+ self.evaluate(id)?.template.layout(self)
}
/// Resolve a user-entered path (relative to the source file) to be
diff --git a/src/library/align.rs b/src/library/align.rs
index 5b50937e..3ffd5ec8 100644
--- a/src/library/align.rs
+++ b/src/library/align.rs
@@ -27,7 +27,7 @@ impl Layout for AlignNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
// The child only needs to expand along an axis if there's no alignment.
let mut pod = regions.clone();
pod.expand &= self.aligns.map_is_none();
@@ -39,7 +39,7 @@ impl Layout for AlignNode {
}
// Layout the child.
- let mut frames = self.child.layout(vm, &pod, passed.chain(&styles));
+ let mut frames = self.child.layout(vm, &pod, passed.chain(&styles))?;
for ((current, base), Constrained { item: frame, cts }) in
regions.iter().zip(&mut frames)
@@ -57,7 +57,7 @@ impl Layout for AlignNode {
cts.exact = current.filter(regions.expand | cts.exact.map_is_some());
}
- frames
+ Ok(frames)
}
}
diff --git a/src/library/columns.rs b/src/library/columns.rs
index 61da6177..049fa8b9 100644
--- a/src/library/columns.rs
+++ b/src/library/columns.rs
@@ -32,7 +32,7 @@ impl Layout for ColumnsNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
// Separating the infinite space into infinite columns does not make
// much sense.
if regions.current.x.is_infinite() {
@@ -59,7 +59,7 @@ impl Layout for ColumnsNode {
};
// Layout the children.
- let mut frames = self.child.layout(vm, &pod, styles).into_iter();
+ let mut frames = self.child.layout(vm, &pod, styles)?.into_iter();
let dir = styles.get(ParNode::DIR);
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
@@ -102,7 +102,7 @@ impl Layout for ColumnsNode {
finished.push(output.constrain(cts));
}
- finished
+ Ok(finished)
}
}
diff --git a/src/library/deco.rs b/src/library/deco.rs
index 92fcf09f..79026288 100644
--- a/src/library/deco.rs
+++ b/src/library/deco.rs
@@ -32,15 +32,15 @@ impl<const L: DecoLine> DecoNode<L> {
}
impl<const L: DecoLine> Show for DecoNode<L> {
- fn show(&self, styles: StyleChain) -> Template {
- self.0.clone().styled(TextNode::LINES, vec![Decoration {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
+ Ok(self.0.clone().styled(TextNode::LINES, vec![Decoration {
line: L,
stroke: styles.get(Self::STROKE),
thickness: styles.get(Self::THICKNESS),
offset: styles.get(Self::OFFSET),
extent: styles.get(Self::EXTENT),
evade: styles.get(Self::EVADE),
- }])
+ }]))
}
}
diff --git a/src/library/flow.rs b/src/library/flow.rs
index 95469b65..135fd327 100644
--- a/src/library/flow.rs
+++ b/src/library/flow.rs
@@ -31,7 +31,7 @@ impl Layout for FlowNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let mut layouter = FlowLayouter::new(regions);
for (child, map) in self.0.iter() {
@@ -56,12 +56,12 @@ impl Layout for FlowNode {
layouter.layout_spacing(*kind);
}
FlowChild::Node(ref node) => {
- layouter.layout_node(vm, node, styles);
+ layouter.layout_node(vm, node, styles)?;
}
}
}
- layouter.finish()
+ Ok(layouter.finish())
}
}
@@ -161,7 +161,12 @@ impl FlowLayouter {
}
/// Layout a node.
- pub fn layout_node(&mut self, vm: &mut Vm, node: &LayoutNode, styles: StyleChain) {
+ pub fn layout_node(
+ &mut self,
+ vm: &mut Vm,
+ node: &LayoutNode,
+ styles: StyleChain,
+ ) -> TypResult<()> {
// Don't even try layouting into a full region.
if self.regions.is_full() {
self.finish_region();
@@ -171,9 +176,9 @@ impl FlowLayouter {
// aligned later.
if let Some(placed) = node.downcast::<PlaceNode>() {
if placed.out_of_flow() {
- let frame = node.layout(vm, &self.regions, styles).remove(0);
+ let frame = node.layout(vm, &self.regions, styles)?.remove(0);
self.items.push(FlowItem::Placed(frame.item));
- return;
+ return Ok(());
}
}
@@ -188,7 +193,7 @@ impl FlowLayouter {
.unwrap_or(Align::Top),
);
- let frames = node.layout(vm, &self.regions, styles);
+ let frames = node.layout(vm, &self.regions, styles)?;
let len = frames.len();
for (i, frame) in frames.into_iter().enumerate() {
// Grow our size, shrink the region and save the frame for later.
@@ -202,6 +207,8 @@ impl FlowLayouter {
self.finish_region();
}
}
+
+ Ok(())
}
/// Finish the frame for one region.
diff --git a/src/library/grid.rs b/src/library/grid.rs
index 78ac375f..5f1edb1c 100644
--- a/src/library/grid.rs
+++ b/src/library/grid.rs
@@ -38,7 +38,7 @@ impl Layout for GridNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
// Prepare grid layout by unifying content and gutter tracks.
let layouter = GridLayouter::new(
self.tracks.as_deref(),
@@ -48,7 +48,7 @@ impl Layout for GridNode {
styles,
);
- // Measure the columsna nd layout the grid row-by-row.
+ // Measure the columns and layout the grid row-by-row.
layouter.layout(vm)
}
}
@@ -205,19 +205,19 @@ impl<'a> GridLayouter<'a> {
}
/// Determines the columns sizes and then layouts the grid row-by-row.
- pub fn layout(mut self, vm: &mut Vm) -> Vec<Constrained<Arc<Frame>>> {
- self.measure_columns(vm);
+ pub fn layout(mut self, vm: &mut Vm) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
+ self.measure_columns(vm)?;
for y in 0 .. self.rows.len() {
// Skip to next region if current one is full, but only for content
// rows, not for gutter rows.
if y % 2 == 0 && self.regions.is_full() {
- self.finish_region(vm);
+ self.finish_region(vm)?;
}
match self.rows[y] {
- TrackSizing::Auto => self.layout_auto_row(vm, y),
- TrackSizing::Linear(v) => self.layout_linear_row(vm, v, y),
+ TrackSizing::Auto => self.layout_auto_row(vm, y)?,
+ TrackSizing::Linear(v) => self.layout_linear_row(vm, v, y)?,
TrackSizing::Fractional(v) => {
self.cts.exact.y = Some(self.full);
self.lrows.push(Row::Fr(v, y));
@@ -226,12 +226,12 @@ impl<'a> GridLayouter<'a> {
}
}
- self.finish_region(vm);
- self.finished
+ self.finish_region(vm)?;
+ Ok(self.finished)
}
/// Determine all column sizes.
- fn measure_columns(&mut self, vm: &mut Vm) {
+ fn measure_columns(&mut self, vm: &mut Vm) -> TypResult<()> {
enum Case {
/// The column sizing is only determined by specified linear sizes.
PurelyLinear,
@@ -277,7 +277,7 @@ impl<'a> GridLayouter<'a> {
let available = self.regions.current.x - linear;
if available >= Length::zero() {
// Determine size of auto columns.
- let (auto, count) = self.measure_auto_columns(vm, available);
+ let (auto, count) = self.measure_auto_columns(vm, available)?;
// If there is remaining space, distribute it to fractional columns,
// otherwise shrink auto columns.
@@ -308,6 +308,8 @@ impl<'a> GridLayouter<'a> {
// Sum up the resolved column sizes once here.
self.used.x = self.rcols.iter().sum();
+
+ Ok(())
}
/// Measure the size that is available to auto columns.
@@ -315,7 +317,7 @@ impl<'a> GridLayouter<'a> {
&mut self,
vm: &mut Vm,
available: Length,
- ) -> (Length, usize) {
+ ) -> TypResult<(Length, usize)> {
let mut auto = Length::zero();
let mut count = 0;
@@ -340,7 +342,7 @@ impl<'a> GridLayouter<'a> {
pod.base.y = v.resolve(self.regions.base.y);
}
- let frame = node.layout(vm, &pod, self.styles).remove(0).item;
+ let frame = node.layout(vm, &pod, self.styles)?.remove(0).item;
resolved.set_max(frame.size.x);
}
}
@@ -350,7 +352,7 @@ impl<'a> GridLayouter<'a> {
count += 1;
}
- (auto, count)
+ Ok((auto, count))
}
/// Distribute remaining space to fractional columns.
@@ -394,7 +396,7 @@ impl<'a> GridLayouter<'a> {
/// Layout a row with automatic height. Such a row may break across multiple
/// regions.
- fn layout_auto_row(&mut self, vm: &mut Vm, y: usize) {
+ fn layout_auto_row(&mut self, vm: &mut Vm, y: usize) -> TypResult<()> {
let mut resolved: Vec<Length> = vec![];
// Determine the size for each region of the row.
@@ -409,7 +411,7 @@ impl<'a> GridLayouter<'a> {
}
let mut sizes = node
- .layout(vm, &pod, self.styles)
+ .layout(vm, &pod, self.styles)?
.into_iter()
.map(|frame| frame.item.size.y);
@@ -427,14 +429,14 @@ impl<'a> GridLayouter<'a> {
// Nothing to layout.
if resolved.is_empty() {
- return;
+ return Ok(());
}
// Layout into a single region.
if let &[first] = resolved.as_slice() {
- let frame = self.layout_single_row(vm, first, y);
+ let frame = self.layout_single_row(vm, first, y)?;
self.push_row(frame);
- return;
+ return Ok(());
}
// Expand all but the last region if the space is not
@@ -449,36 +451,40 @@ impl<'a> GridLayouter<'a> {
}
// Layout into multiple regions.
- let frames = self.layout_multi_row(vm, &resolved, y);
+ let frames = self.layout_multi_row(vm, &resolved, y)?;
let len = frames.len();
for (i, frame) in frames.into_iter().enumerate() {
self.push_row(frame);
if i + 1 < len {
self.cts.exact.y = Some(self.full);
- self.finish_region(vm);
+ self.finish_region(vm)?;
}
}
+
+ Ok(())
}
/// Layout a row with linear height. Such a row cannot break across multiple
/// regions, but it may force a region break.
- fn layout_linear_row(&mut self, vm: &mut Vm, v: Linear, y: usize) {
+ fn layout_linear_row(&mut self, vm: &mut Vm, v: Linear, y: usize) -> TypResult<()> {
let resolved = v.resolve(self.regions.base.y);
- let frame = self.layout_single_row(vm, resolved, y);
+ let frame = self.layout_single_row(vm, resolved, y)?;
// Skip to fitting region.
let height = frame.size.y;
while !self.regions.current.y.fits(height) && !self.regions.in_last() {
self.cts.max.y = Some(self.used.y + height);
- self.finish_region(vm);
+ self.finish_region(vm)?;
// Don't skip multiple regions for gutter and don't push a row.
if y % 2 == 1 {
- return;
+ return Ok(());
}
}
self.push_row(frame);
+
+ Ok(())
}
/// Layout a row with fixed height and return its frame.
@@ -487,7 +493,7 @@ impl<'a> GridLayouter<'a> {
vm: &mut Vm,
height: Length,
y: usize,
- ) -> Frame {
+ ) -> TypResult<Frame> {
let mut output = Frame::new(Size::new(self.used.x, height));
let mut pos = Point::zero();
@@ -502,14 +508,14 @@ impl<'a> GridLayouter<'a> {
.select(self.regions.base, size);
let pod = Regions::one(size, base, Spec::splat(true));
- let frame = node.layout(vm, &pod, self.styles).remove(0);
+ let frame = node.layout(vm, &pod, self.styles)?.remove(0);
output.push_frame(pos, frame.item);
}
pos.x += rcol;
}
- output
+ Ok(output)
}
/// Layout a row spanning multiple regions.
@@ -518,7 +524,7 @@ impl<'a> GridLayouter<'a> {
vm: &mut Vm,
heights: &[Length],
y: usize,
- ) -> Vec<Frame> {
+ ) -> TypResult<Vec<Frame>> {
// Prepare frames.
let mut outputs: Vec<_> = heights
.iter()
@@ -542,7 +548,7 @@ impl<'a> GridLayouter<'a> {
}
// Push the layouted frames into the individual output frames.
- let frames = node.layout(vm, &pod, self.styles);
+ let frames = node.layout(vm, &pod, self.styles)?;
for (output, frame) in outputs.iter_mut().zip(frames) {
output.push_frame(pos, frame.item);
}
@@ -551,7 +557,7 @@ impl<'a> GridLayouter<'a> {
pos.x += rcol;
}
- outputs
+ Ok(outputs)
}
/// Push a row frame into the current region.
@@ -562,7 +568,7 @@ impl<'a> GridLayouter<'a> {
}
/// Finish rows for one region.
- fn finish_region(&mut self, vm: &mut Vm) {
+ fn finish_region(&mut self, vm: &mut Vm) -> TypResult<()> {
// Determine the size of the grid in this region, expanding fully if
// there are fr rows.
let mut size = self.used;
@@ -584,7 +590,7 @@ impl<'a> GridLayouter<'a> {
Row::Fr(v, y) => {
let remaining = self.full - self.used.y;
let height = v.resolve(self.fr, remaining);
- self.layout_single_row(vm, height, y)
+ self.layout_single_row(vm, height, y)?
}
};
@@ -600,6 +606,8 @@ impl<'a> GridLayouter<'a> {
self.used.y = Length::zero();
self.fr = Fractional::zero();
self.cts = Constraints::new(self.expand);
+
+ Ok(())
}
/// Get the node in the cell in column `x` and row `y`.
diff --git a/src/library/heading.rs b/src/library/heading.rs
index 2123116b..2044355e 100644
--- a/src/library/heading.rs
+++ b/src/library/heading.rs
@@ -43,7 +43,7 @@ impl HeadingNode {
}
impl Show for HeadingNode {
- fn show(&self, styles: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
let mut map = StyleMap::new();
let upscale = (1.6 - 0.1 * self.level as f64).max(0.75);
@@ -93,6 +93,8 @@ impl Show for HeadingNode {
seq.push(Template::Vertical(below.into()));
}
- Template::block(Template::sequence(seq).styled_with_map(map))
+ Ok(Template::block(
+ Template::sequence(seq).styled_with_map(map),
+ ))
}
}
diff --git a/src/library/hide.rs b/src/library/hide.rs
index 230300d2..ea2227f1 100644
--- a/src/library/hide.rs
+++ b/src/library/hide.rs
@@ -19,14 +19,14 @@ impl Layout for HideNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
- let mut frames = self.0.layout(vm, regions, styles);
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
+ let mut frames = self.0.layout(vm, regions, styles)?;
// Clear the frames.
for Constrained { item: frame, .. } in &mut frames {
*frame = Arc::new(Frame { elements: vec![], ..**frame });
}
- frames
+ Ok(frames)
}
}
diff --git a/src/library/image.rs b/src/library/image.rs
index 5527fbdc..05877126 100644
--- a/src/library/image.rs
+++ b/src/library/image.rs
@@ -39,7 +39,7 @@ impl Layout for ImageNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let img = vm.images.get(self.0);
let pxw = img.width() as f64;
let pxh = img.height() as f64;
@@ -91,7 +91,7 @@ impl Layout for ImageNode {
frame.link(url);
}
- vec![frame.constrain(Constraints::tight(regions))]
+ Ok(vec![frame.constrain(Constraints::tight(regions))])
}
}
diff --git a/src/library/link.rs b/src/library/link.rs
index 58c7e550..95fff089 100644
--- a/src/library/link.rs
+++ b/src/library/link.rs
@@ -37,7 +37,7 @@ impl LinkNode {
}
impl Show for LinkNode {
- fn show(&self, styles: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
let mut map = StyleMap::new();
map.set(TextNode::LINK, Some(self.url.clone()));
@@ -50,6 +50,6 @@ impl Show for LinkNode {
body = body.underlined();
}
- body.styled_with_map(map)
+ Ok(body.styled_with_map(map))
}
}
diff --git a/src/library/list.rs b/src/library/list.rs
index 7f76a178..08ccfc18 100644
--- a/src/library/list.rs
+++ b/src/library/list.rs
@@ -30,7 +30,7 @@ impl<const L: Labelling> ListNode<L> {
}
impl<const L: Labelling> Show for ListNode<L> {
- fn show(&self, styles: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
let em = styles.get(TextNode::SIZE).abs;
let label_indent = styles.get(Self::LABEL_INDENT).resolve(em);
let body_indent = styles.get(Self::BODY_INDENT).resolve(em);
@@ -40,7 +40,7 @@ impl<const L: Labelling> Show for ListNode<L> {
ORDERED | _ => format_eco!("{}.", self.number.unwrap_or(1)),
};
- Template::block(GridNode {
+ Ok(Template::block(GridNode {
tracks: Spec::with_x(vec![
TrackSizing::Linear(label_indent.into()),
TrackSizing::Auto,
@@ -54,7 +54,7 @@ impl<const L: Labelling> Show for ListNode<L> {
LayoutNode::default(),
self.child.clone(),
],
- })
+ }))
}
}
diff --git a/src/library/math.rs b/src/library/math.rs
index 29367cd5..d3c8b5e5 100644
--- a/src/library/math.rs
+++ b/src/library/math.rs
@@ -22,11 +22,11 @@ impl MathNode {
}
impl Show for MathNode {
- fn show(&self, _: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, _: StyleChain) -> TypResult<Template> {
let mut template = Template::Text(self.formula.trim().into());
if self.display {
template = Template::Block(template.pack());
}
- template.monospaced()
+ Ok(template.monospaced())
}
}
diff --git a/src/library/pad.rs b/src/library/pad.rs
index 84e83939..76647645 100644
--- a/src/library/pad.rs
+++ b/src/library/pad.rs
@@ -37,10 +37,10 @@ impl Layout for PadNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
// Layout child into padded regions.
let pod = regions.map(|size| shrink(size, self.padding));
- let mut frames = self.child.layout(vm, &pod, styles);
+ let mut frames = self.child.layout(vm, &pod, styles)?;
for ((current, base), Constrained { item: frame, cts }) in
regions.iter().zip(&mut frames)
@@ -70,7 +70,7 @@ impl Layout for PadNode {
}
}
- frames
+ Ok(frames)
}
}
diff --git a/src/library/page.rs b/src/library/page.rs
index 155f60dd..160ac1ed 100644
--- a/src/library/page.rs
+++ b/src/library/page.rs
@@ -60,7 +60,7 @@ impl PageNode {
impl PageNode {
/// Layout the page run into a sequence of frames, one per page.
- pub fn layout(&self, vm: &mut Vm, styles: StyleChain) -> Vec<Arc<Frame>> {
+ pub fn layout(&self, vm: &mut Vm, styles: StyleChain) -> TypResult<Vec<Arc<Frame>>> {
// When one of the lengths is infinite the page fits its content along
// that axis.
let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());
@@ -103,11 +103,11 @@ impl PageNode {
// Layout the child.
let expand = size.map(Length::is_finite);
let regions = Regions::repeat(size, size, expand);
- child
- .layout(vm, &regions, styles)
+ Ok(child
+ .layout(vm, &regions, styles)?
.into_iter()
.map(|c| c.item)
- .collect()
+ .collect())
}
}
diff --git a/src/library/par.rs b/src/library/par.rs
index 02633612..dd0ee5d0 100644
--- a/src/library/par.rs
+++ b/src/library/par.rs
@@ -85,7 +85,7 @@ impl Layout for ParNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
// Collect all text into one string used for BiDi analysis.
let text = self.collect_text();
@@ -95,10 +95,10 @@ impl Layout for ParNode {
// Prepare paragraph layout by building a representation on which we can
// do line breaking without layouting each and every line from scratch.
- let layouter = ParLayouter::new(self, vm, regions, &styles, bidi);
+ let layouter = ParLayouter::new(self, vm, regions, &styles, bidi)?;
// Find suitable linebreaks.
- layouter.layout(vm, regions.clone())
+ Ok(layouter.layout(vm, regions.clone()))
}
}
@@ -220,7 +220,7 @@ impl<'a> ParLayouter<'a> {
regions: &Regions,
styles: &'a StyleChain<'a>,
bidi: BidiInfo<'a>,
- ) -> Self {
+ ) -> TypResult<Self> {
let mut items = vec![];
let mut ranges = vec![];
@@ -255,7 +255,7 @@ impl<'a> ParLayouter<'a> {
ParChild::Node(node) => {
let size = Size::new(regions.current.x, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::splat(false));
- let frame = node.layout(vm, &pod, styles).remove(0);
+ let frame = node.layout(vm, &pod, styles)?.remove(0);
items.push(ParItem::Frame(Arc::take(frame.item)));
ranges.push(range);
}
@@ -266,7 +266,7 @@ impl<'a> ParLayouter<'a> {
let align = styles.get(ParNode::ALIGN);
let leading = styles.get(ParNode::LEADING).resolve(em);
- Self { align, leading, bidi, items, ranges }
+ Ok(Self { align, leading, bidi, items, ranges })
}
/// Find first-fit line breaks and build the paragraph.
diff --git a/src/library/place.rs b/src/library/place.rs
index c2c9ac25..9bcd3c37 100644
--- a/src/library/place.rs
+++ b/src/library/place.rs
@@ -26,7 +26,7 @@ impl Layout for PlaceNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let out_of_flow = self.out_of_flow();
// The pod is the base area of the region because for absolute
@@ -37,7 +37,7 @@ impl Layout for PlaceNode {
Regions::one(regions.base, regions.base, expand)
};
- let mut frames = self.0.layout(vm, &pod, styles);
+ let mut frames = self.0.layout(vm, &pod, styles)?;
let Constrained { item: frame, cts } = &mut frames[0];
// If expansion is off, zero all sizes so that we don't take up any
@@ -51,7 +51,7 @@ impl Layout for PlaceNode {
cts.base = regions.base.map(Some);
cts.exact = regions.current.filter(regions.expand | out_of_flow);
- frames
+ Ok(frames)
}
}
diff --git a/src/library/raw.rs b/src/library/raw.rs
index 45733fd0..da926679 100644
--- a/src/library/raw.rs
+++ b/src/library/raw.rs
@@ -40,7 +40,7 @@ impl RawNode {
}
impl Show for RawNode {
- fn show(&self, styles: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
let lang = styles.get_ref(Self::LANG).as_ref();
let foreground = THEME
.settings
@@ -87,7 +87,7 @@ impl Show for RawNode {
template = Template::Block(template.pack());
}
- template.monospaced()
+ Ok(template.monospaced())
}
}
diff --git a/src/library/shape.rs b/src/library/shape.rs
index acb011ea..518254ce 100644
--- a/src/library/shape.rs
+++ b/src/library/shape.rs
@@ -49,7 +49,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let mut frames;
if let Some(child) = &self.0 {
let mut padding = styles.get(Self::PADDING);
@@ -61,7 +61,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
let child = child.clone().padded(Sides::splat(padding));
let mut pod = Regions::one(regions.current, regions.base, regions.expand);
- frames = child.layout(vm, &pod, styles);
+ frames = child.layout(vm, &pod, styles)?;
// Relayout with full expansion into square region to make sure
// the result is really a square or circle.
@@ -77,7 +77,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
pod.current = Size::splat(length);
pod.expand = Spec::splat(true);
- frames = child.layout(vm, &pod, styles);
+ frames = child.layout(vm, &pod, styles)?;
frames[0].cts = Constraints::tight(regions);
}
} else {
@@ -127,7 +127,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
frame.link(url);
}
- frames
+ Ok(frames)
}
}
diff --git a/src/library/stack.rs b/src/library/stack.rs
index 287731b8..c7985d87 100644
--- a/src/library/stack.rs
+++ b/src/library/stack.rs
@@ -31,7 +31,7 @@ impl Layout for StackNode {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let mut layouter = StackLayouter::new(self.dir, regions);
// Spacing to insert before the next node.
@@ -48,13 +48,13 @@ impl Layout for StackNode {
layouter.layout_spacing(kind);
}
- layouter.layout_node(vm, node, styles);
+ layouter.layout_node(vm, node, styles)?;
deferred = self.spacing;
}
}
}
- layouter.finish()
+ Ok(layouter.finish())
}
}
@@ -163,7 +163,12 @@ impl StackLayouter {
}
/// Layout an arbitrary node.
- pub fn layout_node(&mut self, vm: &mut Vm, node: &LayoutNode, styles: StyleChain) {
+ pub fn layout_node(
+ &mut self,
+ vm: &mut Vm,
+ node: &LayoutNode,
+ styles: StyleChain,
+ ) -> TypResult<()> {
if self.regions.is_full() {
self.finish_region();
}
@@ -174,7 +179,7 @@ impl StackLayouter {
.and_then(|node| node.aligns.get(self.axis))
.unwrap_or(self.dir.start().into());
- let frames = node.layout(vm, &self.regions, styles);
+ let frames = node.layout(vm, &self.regions, styles)?;
let len = frames.len();
for (i, frame) in frames.into_iter().enumerate() {
// Grow our size, shrink the region and save the frame for later.
@@ -188,6 +193,8 @@ impl StackLayouter {
self.finish_region();
}
}
+
+ Ok(())
}
/// Advance to the next region.
diff --git a/src/library/table.rs b/src/library/table.rs
index dfefa21d..8c088c09 100644
--- a/src/library/table.rs
+++ b/src/library/table.rs
@@ -55,7 +55,7 @@ impl TableNode {
}
impl Show for TableNode {
- fn show(&self, styles: StyleChain) -> Template {
+ fn show(&self, _: &mut Vm, styles: StyleChain) -> TypResult<Template> {
let primary = styles.get(Self::PRIMARY);
let secondary = styles.get(Self::SECONDARY);
let thickness = styles.get(Self::THICKNESS);
@@ -85,10 +85,10 @@ impl Show for TableNode {
})
.collect();
- Template::block(GridNode {
+ Ok(Template::block(GridNode {
tracks: self.tracks.clone(),
gutter: self.gutter.clone(),
children,
- })
+ }))
}
}
diff --git a/src/library/text.rs b/src/library/text.rs
index 9fbc8605..721a8eac 100644
--- a/src/library/text.rs
+++ b/src/library/text.rs
@@ -123,8 +123,8 @@ impl StrongNode {
}
impl Show for StrongNode {
- fn show(&self, _: StyleChain) -> Template {
- self.0.clone().styled(TextNode::STRONG, true)
+ fn show(&self, _: &mut Vm, _: StyleChain) -> TypResult<Template> {
+ Ok(self.0.clone().styled(TextNode::STRONG, true))
}
}
@@ -140,8 +140,8 @@ impl EmphNode {
}
impl Show for EmphNode {
- fn show(&self, _: StyleChain) -> Template {
- self.0.clone().styled(TextNode::EMPH, true)
+ fn show(&self, _: &mut Vm, _: StyleChain) -> TypResult<Template> {
+ Ok(self.0.clone().styled(TextNode::EMPH, true))
}
}
diff --git a/src/library/transform.rs b/src/library/transform.rs
index 91d4b574..5cdb2f6f 100644
--- a/src/library/transform.rs
+++ b/src/library/transform.rs
@@ -49,9 +49,9 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
vm: &mut Vm,
regions: &Regions,
styles: StyleChain,
- ) -> Vec<Constrained<Arc<Frame>>> {
+ ) -> TypResult<Vec<Constrained<Arc<Frame>>>> {
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
- let mut frames = self.child.layout(vm, regions, styles);
+ let mut frames = self.child.layout(vm, regions, styles)?;
for Constrained { item: frame, .. } in &mut frames {
let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.resolve(s));
@@ -62,7 +62,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
Arc::make_mut(frame).transform(transform);
}
- frames
+ Ok(frames)
}
}
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 75602057..626fc113 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -275,14 +275,13 @@ fn test_part(
ok &= test_reparse(ctx.sources.get(id).src(), i, rng);
let mut vm = Vm::new(ctx);
- let (frames, mut errors) = match vm.evaluate(id) {
- Ok(module) => {
+ let (frames, mut errors) = match vm.typeset(id) {
+ Ok(mut frames) => {
+ let module = vm.evaluate(id).unwrap();
if debug {
println!("Template: {:#?}", module.template);
}
- let mut frames = module.template.layout(&mut vm);
-
#[cfg(feature = "layout-cache")]
(ok &= test_incremental(ctx, i, &module.template, &frames));
@@ -499,7 +498,7 @@ fn test_incremental(
ctx.layout_cache.turnaround();
- let cached = silenced(|| template.layout(&mut Vm::new(ctx)));
+ let cached = silenced(|| template.layout(&mut Vm::new(ctx)).unwrap());
let total = reference.levels() - 1;
let misses = ctx
.layout_cache