summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exec/context.rs90
-rw-r--r--src/exec/mod.rs22
-rw-r--r--src/layout/frame.rs102
-rw-r--r--src/library/elements.rs14
-rw-r--r--src/library/layout.rs28
5 files changed, 127 insertions, 129 deletions
diff --git a/src/exec/context.rs b/src/exec/context.rs
index 2b0ef9fa..d8ce6528 100644
--- a/src/exec/context.rs
+++ b/src/exec/context.rs
@@ -35,57 +35,55 @@ impl ExecContext {
}
}
- /// Execute a template and return the result as a stack node.
- pub fn exec_template_stack(&mut self, template: &Template) -> StackNode {
- self.exec_stack(|ctx| template.exec(ctx))
+ /// Push a word space into the active paragraph.
+ pub fn space(&mut self) {
+ self.stack.par.push_soft(self.make_text_node(' '));
}
- /// Execute a syntax tree with a map and return the result as a stack node.
- pub fn exec_tree_stack(&mut self, tree: &SyntaxTree, map: &ExprMap) -> StackNode {
- self.exec_stack(|ctx| tree.exec_with_map(ctx, map))
+ /// Apply a forced line break.
+ pub fn linebreak(&mut self) {
+ self.stack.par.push_hard(self.make_text_node('\n'));
}
- /// Execute something and return the result as a stack node.
- pub fn exec_stack(&mut self, f: impl FnOnce(&mut Self)) -> StackNode {
- let snapshot = self.state.clone();
- let page = self.page.take();
- let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state));
-
- f(self);
+ /// Apply a forced paragraph break.
+ pub fn parbreak(&mut self) {
+ let amount = self.state.par_spacing();
+ self.stack.finish_par(&self.state);
+ self.stack.push_soft(StackChild::Spacing(amount.into()));
+ }
- self.state = snapshot;
- self.page = page;
- mem::replace(&mut self.stack, stack).build()
+ /// Apply a forced page break.
+ pub fn pagebreak(&mut self, keep: bool, hard: bool) {
+ if let Some(builder) = &mut self.page {
+ let page = mem::replace(builder, PageBuilder::new(&self.state, hard));
+ let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state));
+ self.tree.runs.extend(page.build(stack.build(), keep));
+ }
}
/// Push text into the active paragraph.
///
/// The text is split into lines at newlines.
- pub fn push_text(&mut self, text: impl Into<EcoString>) {
+ pub fn text(&mut self, text: impl Into<EcoString>) {
self.stack.par.push(self.make_text_node(text));
}
/// Push text, but in monospace.
- pub fn push_monospace_text(&mut self, text: impl Into<EcoString>) {
+ pub fn text_mono(&mut self, text: impl Into<EcoString>) {
let prev = Rc::clone(&self.state.font);
self.state.font_mut().monospace = true;
- self.push_text(text);
+ self.text(text);
self.state.font = prev;
}
- /// Push a word space into the active paragraph.
- pub fn push_word_space(&mut self) {
- self.stack.par.push_soft(self.make_text_node(' '));
- }
-
- /// Push any node into the active paragraph.
- pub fn push_into_par(&mut self, node: impl Into<LayoutNode>) {
+ /// Push an inline node into the active paragraph.
+ pub fn inline(&mut self, node: impl Into<LayoutNode>) {
let align = self.state.aligns.cross;
self.stack.par.push(ParChild::Any(node.into(), align));
}
- /// Push any node into the active stack.
- pub fn push_into_stack(&mut self, node: impl Into<LayoutNode>) {
+ /// Push a block node into the active stack, finishing the active paragraph.
+ pub fn block(&mut self, node: impl Into<LayoutNode>) {
self.parbreak();
let aligns = self.state.aligns;
self.stack.push(StackChild::Any(node.into(), aligns));
@@ -93,7 +91,7 @@ impl ExecContext {
}
/// Push spacing into the active paragraph or stack depending on the `axis`.
- pub fn push_spacing(&mut self, axis: GenAxis, amount: Linear) {
+ pub fn spacing(&mut self, axis: GenAxis, amount: Linear) {
match axis {
GenAxis::Main => {
self.stack.finish_par(&self.state);
@@ -105,25 +103,27 @@ impl ExecContext {
}
}
- /// Apply a forced line break.
- pub fn linebreak(&mut self) {
- self.stack.par.push_hard(self.make_text_node('\n'));
+ /// Execute a template and return the result as a stack node.
+ pub fn exec_template(&mut self, template: &Template) -> StackNode {
+ self.exec_to_stack(|ctx| template.exec(ctx))
}
- /// Apply a forced paragraph break.
- pub fn parbreak(&mut self) {
- let amount = self.state.par_spacing();
- self.stack.finish_par(&self.state);
- self.stack.push_soft(StackChild::Spacing(amount.into()));
+ /// Execute a syntax tree with a map and return the result as a stack node.
+ pub fn exec_tree(&mut self, tree: &SyntaxTree, map: &ExprMap) -> StackNode {
+ self.exec_to_stack(|ctx| tree.exec_with_map(ctx, map))
}
- /// Apply a forced page break.
- pub fn pagebreak(&mut self, keep: bool, hard: bool) {
- if let Some(builder) = &mut self.page {
- let page = mem::replace(builder, PageBuilder::new(&self.state, hard));
- let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state));
- self.tree.runs.extend(page.build(stack.build(), keep));
- }
+ /// Execute something and return the result as a stack node.
+ pub fn exec_to_stack(&mut self, f: impl FnOnce(&mut Self)) -> StackNode {
+ let snapshot = self.state.clone();
+ let page = self.page.take();
+ let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state));
+
+ f(self);
+
+ self.state = snapshot;
+ self.page = page;
+ mem::replace(&mut self.stack, stack).build()
}
/// Finish execution and return the created layout tree.
@@ -133,6 +133,8 @@ impl ExecContext {
self.tree
}
+ /// Construct a text node with the given text and settings from the active
+ /// state.
fn make_text_node(&self, text: impl Into<EcoString>) -> ParChild {
ParChild::Text(
text.into(),
diff --git a/src/exec/mod.rs b/src/exec/mod.rs
index 63e47995..16fd75f8 100644
--- a/src/exec/mod.rs
+++ b/src/exec/mod.rs
@@ -51,8 +51,8 @@ impl ExecWithMap for SyntaxTree {
impl ExecWithMap for SyntaxNode {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
match self {
- Self::Space => ctx.push_word_space(),
- Self::Text(text) => ctx.push_text(text),
+ Self::Space => ctx.space(),
+ Self::Text(text) => ctx.text(text),
Self::Linebreak(_) => ctx.linebreak(),
Self::Parbreak(_) => ctx.parbreak(),
Self::Strong(_) => ctx.state.font_mut().strong ^= true,
@@ -72,7 +72,7 @@ impl Exec for RawNode {
ctx.parbreak();
}
- ctx.push_monospace_text(&self.text);
+ ctx.text_mono(&self.text);
if self.block {
ctx.parbreak();
@@ -112,9 +112,9 @@ impl ExecWithMap for EnumItem {
}
fn exec_item(ctx: &mut ExecContext, label: EcoString, body: &SyntaxTree, map: &ExprMap) {
- let label = ctx.exec_stack(|ctx| ctx.push_text(label));
- let body = ctx.exec_tree_stack(body, map);
- ctx.push_into_stack(StackNode {
+ let label = ctx.exec_to_stack(|ctx| ctx.text(label));
+ let body = ctx.exec_tree(body, map);
+ ctx.block(StackNode {
dirs: Gen::new(ctx.state.dirs.main, ctx.state.dirs.cross),
aspect: None,
children: vec![
@@ -129,13 +129,13 @@ impl Exec for Value {
fn exec(&self, ctx: &mut ExecContext) {
match self {
Value::None => {}
- Value::Int(v) => ctx.push_text(v.to_string()),
- Value::Float(v) => ctx.push_text(v.to_string()),
- Value::Str(v) => ctx.push_text(v),
+ Value::Int(v) => ctx.text(v.to_string()),
+ Value::Float(v) => ctx.text(v.to_string()),
+ Value::Str(v) => ctx.text(v),
Value::Template(v) => v.exec(ctx),
// For values which can't be shown "naturally", we print the
// representation in monospace.
- other => ctx.push_monospace_text(other.to_string()),
+ other => ctx.text_mono(other.to_string()),
}
}
}
@@ -153,7 +153,7 @@ impl Exec for TemplateNode {
match self {
Self::Tree(v) => v.exec(ctx),
Self::Func(v) => v.exec(ctx),
- Self::Str(v) => ctx.push_text(v),
+ Self::Str(v) => ctx.text(v),
}
}
}
diff --git a/src/layout/frame.rs b/src/layout/frame.rs
index 6d5cc2f3..2e3b838e 100644
--- a/src/layout/frame.rs
+++ b/src/layout/frame.rs
@@ -19,37 +19,12 @@ pub struct Frame {
children: Vec<(Point, Child)>,
}
-/// An iterator over all elements in a frame, alongside with their positions.
-#[derive(Debug, Clone)]
-pub struct ElementIter<'a> {
- stack: Vec<(usize, Point, &'a Frame)>,
-}
-
-impl<'a> Iterator for ElementIter<'a> {
- type Item = (Point, &'a Element);
-
- /// Get the next element, if any.
- fn next(&mut self) -> Option<Self::Item> {
- let (cursor, offset, frame) = self.stack.last_mut()?;
- match frame.children.get(*cursor) {
- Some((pos, Child::Frame(f))) => {
- let new_offset = *offset + *pos;
- self.stack.push((0, new_offset, f.as_ref()));
- self.next()
- }
- Some((pos, Child::Element(e))) => {
- *cursor += 1;
- Some((*offset + *pos, e))
- }
- None => {
- self.stack.pop();
- if let Some((cursor, _, _)) = self.stack.last_mut() {
- *cursor += 1;
- }
- self.next()
- }
- }
- }
+/// A frame can contain multiple children: elements or other frames, complete
+/// with their children.
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+enum Child {
+ Element(Element),
+ Frame(Rc<Frame>),
}
impl Frame {
@@ -86,23 +61,46 @@ impl Frame {
}
}
- /// Wraps the frame with constraints.
+ /// Wrap the frame with constraints.
pub fn constrain(self, constraints: Constraints) -> Constrained<Rc<Self>> {
Constrained { item: Rc::new(self), constraints }
}
- /// Returns an iterator over all elements in the frame and its children.
- pub fn elements(&self) -> ElementIter {
- ElementIter { stack: vec![(0, Point::zero(), self)] }
+ /// An iterator over all elements in the frame and its children.
+ pub fn elements(&self) -> Elements {
+ Elements { stack: vec![(0, Point::zero(), self)] }
}
}
-/// A frame can contain multiple children: elements or other frames, complete
-/// with their children.
-#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
-enum Child {
- Element(Element),
- Frame(Rc<Frame>),
+/// An iterator over all elements in a frame, alongside with their positions.
+pub struct Elements<'a> {
+ stack: Vec<(usize, Point, &'a Frame)>,
+}
+
+impl<'a> Iterator for Elements<'a> {
+ type Item = (Point, &'a Element);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let (cursor, offset, frame) = self.stack.last_mut()?;
+ match frame.children.get(*cursor) {
+ Some((pos, Child::Frame(f))) => {
+ let new_offset = *offset + *pos;
+ self.stack.push((0, new_offset, f.as_ref()));
+ self.next()
+ }
+ Some((pos, Child::Element(e))) => {
+ *cursor += 1;
+ Some((*offset + *pos, e))
+ }
+ None => {
+ self.stack.pop();
+ if let Some((cursor, _, _)) = self.stack.last_mut() {
+ *cursor += 1;
+ }
+ self.next()
+ }
+ }
+ }
}
/// The building block frames are composed of.
@@ -130,17 +128,6 @@ pub struct Text {
pub glyphs: Vec<Glyph>,
}
-/// A glyph in a run of shaped text.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
-pub struct Glyph {
- /// The glyph's index in the face.
- pub id: u16,
- /// The advance width of the glyph.
- pub x_advance: Length,
- /// The horizontal offset of the glyph.
- pub x_offset: Length,
-}
-
impl Text {
/// Encode the glyph ids into a big-endian byte buffer.
pub fn encode_glyphs_be(&self) -> Vec<u8> {
@@ -153,6 +140,17 @@ impl Text {
}
}
+/// A glyph in a run of shaped text.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
+pub struct Glyph {
+ /// The glyph's index in the face.
+ pub id: u16,
+ /// The advance width of the glyph.
+ pub x_advance: Length,
+ /// The horizontal offset of the glyph.
+ pub x_offset: Length,
+}
+
/// A geometric shape.
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum Geometry {
diff --git a/src/library/elements.rs b/src/library/elements.rs
index 1ad56a81..f4577084 100644
--- a/src/library/elements.rs
+++ b/src/library/elements.rs
@@ -24,7 +24,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
})?;
Ok(Value::template(move |ctx| {
- ctx.push_into_par(ImageNode { id, width, height })
+ ctx.inline(ImageNode { id, width, height })
}))
}
@@ -62,19 +62,19 @@ fn rect_impl(
body: Template,
) -> Value {
Value::template(move |ctx| {
- let mut stack = ctx.exec_template_stack(&body);
+ let mut stack = ctx.exec_template(&body);
stack.aspect = aspect;
let fixed = FixedNode { width, height, child: stack.into() };
if let Some(fill) = fill {
- ctx.push_into_par(BackgroundNode {
+ ctx.inline(BackgroundNode {
shape: BackgroundShape::Rect,
fill: Paint::Color(fill),
child: fixed.into(),
});
} else {
- ctx.push_into_par(fixed);
+ ctx.inline(fixed);
}
})
}
@@ -117,7 +117,7 @@ fn ellipse_impl(
// perfectly into the ellipse.
const PAD: f64 = 0.5 - SQRT_2 / 4.0;
- let mut stack = ctx.exec_template_stack(&body);
+ let mut stack = ctx.exec_template(&body);
stack.aspect = aspect;
let fixed = FixedNode {
@@ -131,13 +131,13 @@ fn ellipse_impl(
};
if let Some(fill) = fill {
- ctx.push_into_par(BackgroundNode {
+ ctx.inline(BackgroundNode {
shape: BackgroundShape::Ellipse,
fill: Paint::Color(fill),
child: fixed.into(),
});
} else {
- ctx.push_into_par(fixed);
+ ctx.inline(fixed);
}
})
}
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 67e58606..e910139c 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -82,7 +82,7 @@ pub fn pagebreak(_: &mut EvalContext, _: &mut Arguments) -> TypResult<Value> {
pub fn h(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
let spacing = args.expect("spacing")?;
Ok(Value::template(move |ctx| {
- ctx.push_spacing(GenAxis::Cross, spacing);
+ ctx.spacing(GenAxis::Cross, spacing);
}))
}
@@ -90,7 +90,7 @@ pub fn h(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
pub fn v(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
let spacing = args.expect("spacing")?;
Ok(Value::template(move |ctx| {
- ctx.push_spacing(GenAxis::Main, spacing);
+ ctx.spacing(GenAxis::Main, spacing);
}))
}
@@ -134,8 +134,8 @@ pub fn boxed(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
let height = args.named("height")?;
let body = args.eat().unwrap_or_default();
Ok(Value::template(move |ctx| {
- let child = ctx.exec_template_stack(&body).into();
- ctx.push_into_par(FixedNode { width, height, child });
+ let child = ctx.exec_template(&body).into();
+ ctx.inline(FixedNode { width, height, child });
}))
}
@@ -143,8 +143,8 @@ pub fn boxed(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
pub fn block(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
let body = args.expect("body")?;
Ok(Value::template(move |ctx| {
- let block = ctx.exec_template_stack(&body);
- ctx.push_into_stack(block);
+ let block = ctx.exec_template(&body);
+ ctx.block(block);
}))
}
@@ -165,8 +165,8 @@ pub fn pad(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
);
Ok(Value::template(move |ctx| {
- let child = ctx.exec_template_stack(&body).into();
- ctx.push_into_stack(PadNode { padding, child });
+ let child = ctx.exec_template(&body).into();
+ ctx.block(PadNode { padding, child });
}))
}
@@ -179,7 +179,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
let children = children
.iter()
.map(|child| {
- let child = ctx.exec_template_stack(child).into();
+ let child = ctx.exec_template(child).into();
StackChild::Any(child, ctx.state.aligns)
})
.collect();
@@ -192,7 +192,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
dirs.cross = ctx.state.dirs.main;
}
- ctx.push_into_stack(StackNode { dirs, aspect: None, children });
+ ctx.block(StackNode { dirs, aspect: None, children });
}))
}
@@ -220,10 +220,8 @@ pub fn grid(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
);
Ok(Value::template(move |ctx| {
- let children = children
- .iter()
- .map(|child| ctx.exec_template_stack(child).into())
- .collect();
+ let children =
+ children.iter().map(|child| ctx.exec_template(child).into()).collect();
let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(ctx.state.dirs);
@@ -243,7 +241,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Arguments) -> TypResult<Value> {
};
}
- ctx.push_into_stack(GridNode {
+ ctx.block(GridNode {
dirs,
tracks: tracks.clone(),
gutter: gutter.clone(),