summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/func/mod.rs4
-rw-r--r--src/layout/flex.rs12
-rw-r--r--src/layout/mod.rs1
-rw-r--r--src/layout/stacked.rs6
-rw-r--r--src/layout/tree.rs19
-rw-r--r--src/library/axes.rs43
-rw-r--r--src/library/boxed.rs21
-rw-r--r--src/library/mod.rs19
-rw-r--r--src/library/spacing.rs81
-rw-r--r--src/library/structure.rs172
-rw-r--r--src/library/style.rs14
-rw-r--r--src/macros.rs7
-rw-r--r--tests/layouting.rs2
13 files changed, 193 insertions, 208 deletions
diff --git a/src/func/mod.rs b/src/func/mod.rs
index f59c1ec0..27dceee3 100644
--- a/src/func/mod.rs
+++ b/src/func/mod.rs
@@ -20,6 +20,7 @@ pub mod prelude {
pub use crate::size::{Size, Size2D, SizeBox};
pub use crate::style::{PageStyle, TextStyle};
pub use super::helpers::*;
+ pub use Command::*;
}
/// Typesetting function types.
@@ -93,6 +94,9 @@ pub enum Command<'a> {
Add(Layout),
AddMultiple(MultiLayout),
+ AddPrimarySpace(Size),
+ AddSecondarySpace(Size),
+
FinishRun,
FinishBox,
FinishLayout,
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index 3155a13a..bae700ce 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -67,7 +67,7 @@ impl FlexLayouter {
/// Create a new flex layouter.
pub fn new(ctx: FlexContext) -> FlexLayouter {
let stack = StackLayouter::new(StackContext {
- spaces: ctx.spaces,
+ spaces: ctx.spaces.clone(),
axes: ctx.axes,
shrink_to_fit: ctx.shrink_to_fit,
});
@@ -118,7 +118,7 @@ impl FlexLayouter {
}
/// Update the axes in use by this flex layouter.
- pub fn set_axes(&self, axes: LayoutAxes) {
+ pub fn set_axes(&mut self, axes: LayoutAxes) {
self.units.push(FlexUnit::SetAxes(axes));
}
@@ -246,7 +246,7 @@ impl FlexLayouter {
Ok(())
}
- fn finish_aligned_run(&mut self) -> LayoutResult<()> {
+ fn finish_aligned_run(&mut self) {
let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x);
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
@@ -259,13 +259,11 @@ impl FlexLayouter {
self.merged_dimensions.y = crate::size::max(self.merged_dimensions.y, self.run.size.y);
self.run.size = Size2D::zero();
-
- Ok(())
}
/// This layouter's context.
- pub fn ctx(&self) -> FlexContext {
- self.ctx
+ pub fn ctx(&self) -> &FlexContext {
+ &self.ctx
}
pub fn remaining(&self) -> LayoutResult<LayoutSpaces> {
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 420c90bc..fb63ff86 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1,6 +1,5 @@
//! The core layouting engine.
-use std::borrow::Cow;
use std::io::{self, Write};
use smallvec::SmallVec;
diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs
index 77af6f38..8113a4b7 100644
--- a/src/layout/stacked.rs
+++ b/src/layout/stacked.rs
@@ -93,7 +93,7 @@ impl StackLayouter {
}
/// Update the axes in use by this stack layouter.
- pub fn set_axes(&self, axes: LayoutAxes) {
+ pub fn set_axes(&mut self, axes: LayoutAxes) {
if axes != self.ctx.axes {
self.finish_boxes();
self.usable = self.remains();
@@ -171,8 +171,8 @@ impl StackLayouter {
}
/// This layouter's context.
- pub fn ctx(&self) -> StackContext {
- self.ctx
+ pub fn ctx(&self) -> &StackContext {
+ &self.ctx
}
/// The (generalized) usable area of the current space.
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 4742de23..11e83209 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -11,21 +11,21 @@ pub fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiL
struct TreeLayouter<'a, 'p> {
ctx: LayoutContext<'a, 'p>,
flex: FlexLayouter,
- style: Cow<'a, TextStyle>,
+ style: TextStyle,
}
impl<'a, 'p> TreeLayouter<'a, 'p> {
/// Create a new layouter.
fn new(ctx: LayoutContext<'a, 'p>) -> TreeLayouter<'a, 'p> {
TreeLayouter {
- ctx,
flex: FlexLayouter::new(FlexContext {
flex_spacing: flex_spacing(&ctx.style),
- spaces: ctx.spaces,
+ spaces: ctx.spaces.clone(),
axes: ctx.axes,
shrink_to_fit: ctx.shrink_to_fit,
}),
- style: Cow::Borrowed(ctx.style),
+ style: ctx.style.clone(),
+ ctx,
}
}
@@ -52,9 +52,9 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
}
}
- Node::ToggleItalics => self.style.to_mut().toggle_class(FontClass::Italic),
- Node::ToggleBold => self.style.to_mut().toggle_class(FontClass::Bold),
- Node::ToggleMonospace => self.style.to_mut().toggle_class(FontClass::Monospace),
+ Node::ToggleItalics => self.style.toggle_class(FontClass::Italic),
+ Node::ToggleBold => self.style.toggle_class(FontClass::Bold),
+ Node::ToggleMonospace => self.style.toggle_class(FontClass::Monospace),
Node::Func(func) => self.layout_func(func)?,
}
@@ -85,13 +85,16 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
Command::Add(layout) => self.flex.add(layout),
Command::AddMultiple(layouts) => self.flex.add_multiple(layouts),
+ Command::AddPrimarySpace(space) => self.flex.add_primary_space(space),
+ Command::AddSecondarySpace(space) => self.flex.add_secondary_space(space)?,
+
Command::FinishRun => self.flex.add_run_break(),
Command::FinishBox => self.flex.finish_box()?,
Command::FinishLayout => self.flex.finish_layout(true)?,
Command::BreakParagraph => self.break_paragraph()?,
- Command::SetStyle(style) => *self.style.to_mut() = style,
+ Command::SetStyle(style) => self.style = style,
Command::SetAxes(axes) => {
self.flex.set_axes(axes);
self.ctx.axes = axes;
diff --git a/src/library/axes.rs b/src/library/axes.rs
new file mode 100644
index 00000000..62e0078f
--- /dev/null
+++ b/src/library/axes.rs
@@ -0,0 +1,43 @@
+use crate::func::prelude::*;
+
+/// 📐 `align`: Aligns content in different ways.
+#[derive(Debug, PartialEq)]
+pub struct Align {
+ body: Option<SyntaxTree>,
+ alignment: Alignment,
+}
+
+function! {
+ data: Align,
+
+ parse(args, body, ctx) {
+ let body = parse!(optional: body, ctx);
+ let arg = args.get_pos::<ArgIdent>()?;
+ let alignment = match arg.val {
+ "left" | "origin" => Alignment::Origin,
+ "center" => Alignment::Center,
+ "right" | "end" => Alignment::End,
+ s => err!("invalid alignment specifier: {}", s),
+ };
+ args.done()?;
+
+ Ok(Align {
+ body,
+ alignment,
+ })
+ }
+
+ layout(this, ctx) {
+ let mut new_axes = ctx.axes;
+ new_axes.primary.alignment = this.alignment;
+
+ Ok(match &this.body {
+ Some(body) => commands![
+ SetAxes(new_axes),
+ LayoutTree(body),
+ SetAxes(ctx.axes),
+ ],
+ None => commands![Command::SetAxes(new_axes)]
+ })
+ }
+}
diff --git a/src/library/boxed.rs b/src/library/boxed.rs
new file mode 100644
index 00000000..e8debca4
--- /dev/null
+++ b/src/library/boxed.rs
@@ -0,0 +1,21 @@
+use crate::func::prelude::*;
+
+/// `box`: Layouts content into a box.
+#[derive(Debug, PartialEq)]
+pub struct Boxed {
+ body: SyntaxTree,
+}
+
+function! {
+ data: Boxed,
+
+ parse(args, body, ctx) {
+ args.done()?;
+ let body = parse!(required: body, ctx);
+ Ok(Boxed { body })
+ }
+
+ layout(this, ctx) {
+ Ok(commands![AddMultiple(layout_tree(&this.body, ctx)?)])
+ }
+}
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 74f77204..d795d488 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -2,22 +2,23 @@
use crate::func::Scope;
-mod structure;
-mod style;
-
-pub use structure::*;
-pub use style::*;
+pub_use_mod!(boxed);
+pub_use_mod!(axes);
+pub_use_mod!(spacing);
+pub_use_mod!(style);
/// Create a scope with all standard functions.
pub fn std() -> Scope {
let mut std = Scope::new();
- std.add::<Align>("align");
std.add::<Boxed>("box");
- std.add::<Linebreak>("line.break");
- std.add::<Linebreak>("n");
- std.add::<Pagebreak>("page.break");
+ std.add::<Align>("align");
+
+ std.add::<LineBreak>("n");
+ std.add::<LineBreak>("line.break");
+ std.add::<ParagraphBreak>("paragraph.break");
+ std.add::<PageBreak>("page.break");
std.add::<HorizontalSpace>("h");
std.add::<VerticalSpace>("v");
diff --git a/src/library/spacing.rs b/src/library/spacing.rs
new file mode 100644
index 00000000..afd26d80
--- /dev/null
+++ b/src/library/spacing.rs
@@ -0,0 +1,81 @@
+use crate::func::prelude::*;
+
+/// `line.break`, `n`: Ends the current line.
+#[derive(Debug, PartialEq)]
+pub struct LineBreak;
+
+function! {
+ data: LineBreak,
+ parse: plain,
+ layout(_, _) { Ok(commands![FinishRun]) }
+}
+
+/// `paragraph.break`: Ends the current paragraph.
+///
+/// This has the same effect as two subsequent newlines.
+#[derive(Debug, PartialEq)]
+pub struct ParagraphBreak;
+
+function! {
+ data: ParagraphBreak,
+ parse: plain,
+ layout(_, _) { Ok(commands![FinishBox]) }
+}
+
+/// `page.break`: Ends the current page.
+#[derive(Debug, PartialEq)]
+pub struct PageBreak;
+
+function! {
+ data: PageBreak,
+ parse: plain,
+ layout(_, _) { Ok(commands![FinishLayout]) }
+}
+
+macro_rules! space_func {
+ ($ident:ident, $doc:expr, $var:ident => $command:expr) => (
+ #[doc = $doc]
+ #[derive(Debug, PartialEq)]
+ pub struct $ident(Spacing);
+
+ function! {
+ data: $ident,
+
+ parse(args, body, _ctx) {
+ parse!(forbidden: body);
+
+ let arg = args.get_pos::<ArgExpr>()?;
+ let spacing = match arg.val {
+ Expression::Size(s) => Spacing::Absolute(*s),
+ Expression::Num(f) => Spacing::Relative(*f as f32),
+ _ => err!("invalid spacing, expected size or number"),
+ };
+
+ Ok($ident(spacing))
+ }
+
+ layout(this, ctx) {
+ let $var = match this.0 {
+ Spacing::Absolute(s) => s,
+ Spacing::Relative(f) => f * ctx.style.font_size,
+ };
+
+ Ok(commands![$command])
+ }
+ }
+ );
+}
+
+/// Absolute or font-relative spacing.
+#[derive(Debug, PartialEq)]
+enum Spacing {
+ Absolute(Size),
+ Relative(f32),
+}
+
+// FIXME: h != primary and v != secondary.
+space_func!(HorizontalSpace, "📖 `h`: Adds horizontal whitespace.",
+ space => AddPrimarySpace(space));
+
+space_func!(VerticalSpace, "📑 `v`: Adds vertical whitespace.",
+ space => AddSecondarySpace(space));
diff --git a/src/library/structure.rs b/src/library/structure.rs
deleted file mode 100644
index 2dbf33ff..00000000
--- a/src/library/structure.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-use crate::func::prelude::*;
-use Command::*;
-
-/// ↩ `line.break`, `n`: Ends the current line.
-#[derive(Debug, PartialEq)]
-pub struct Linebreak;
-
-function! {
- data: Linebreak,
- parse: plain,
- layout(_, _) { Ok(commands![BreakFlex]) }
-}
-
-/// ↕ `paragraph.break`: Ends the current paragraph.
-///
-/// This has the same effect as two subsequent newlines.
-#[derive(Debug, PartialEq)]
-pub struct Parbreak;
-
-function! {
- data: Parbreak,
- parse: plain,
- layout(_, _) { Ok(commands![FinishFlex]) }
-}
-
-/// 📜 `page.break`: Ends the current page.
-#[derive(Debug, PartialEq)]
-pub struct Pagebreak;
-
-function! {
- data: Pagebreak,
- parse: plain,
- layout(_, _) { Ok(commands![BreakStack]) }
-}
-
-/// 📐 `align`: Aligns content in different ways.
-///
-/// **Positional arguments:**
-/// - `left`, `right` or `center` _(required)_.
-#[derive(Debug, PartialEq)]
-pub struct Align {
- body: Option<SyntaxTree>,
- alignment: Alignment,
-}
-
-function! {
- data: Align,
-
- parse(args, body, ctx) {
- let body = parse!(optional: body, ctx);
- let arg = args.get_pos::<ArgIdent>()?;
- let alignment = match arg.val {
- "left" => Alignment::Left,
- "right" => Alignment::Right,
- "center" => Alignment::Center,
- s => err!("invalid alignment specifier: {}", s),
- };
- args.done()?;
-
- Ok(Align {
- body,
- alignment,
- })
- }
-
- layout(this, ctx) {
- Ok(commands![match &this.body {
- Some(body) => {
- AddMany(layout_tree(body, LayoutContext {
- alignment: this.alignment,
- .. ctx
- })?)
- }
- None => SetAlignment(this.alignment)
- }])
- }
-}
-
-/// 📦 `box`: Layouts content into a box.
-///
-/// **Positional arguments:** None.
-///
-/// **Keyword arguments:**
-/// - flow: either `horizontal` or `vertical` _(optional)_.
-#[derive(Debug, PartialEq)]
-pub struct Boxed {
- body: SyntaxTree,
- flow: Flow,
-}
-
-function! {
- data: Boxed,
-
- parse(args, body, ctx) {
- let body = parse!(required: body, ctx);
-
- let mut flow = Flow::Vertical;
- if let Some(ident) = args.get_key_opt::<ArgIdent>("flow")? {
- flow = match ident.val {
- "vertical" => Flow::Vertical,
- "horizontal" => Flow::Horizontal,
- f => err!("invalid flow specifier: {}", f),
- };
- }
- args.done()?;
-
- Ok(Boxed {
- body,
- flow,
- })
- }
-
- layout(this, ctx) {
- Ok(commands![
- AddMany(layout_tree(&this.body, LayoutContext {
- flow: this.flow,
- .. ctx
- })?)
- ])
- }
-}
-
-macro_rules! spacefunc {
- ($ident:ident, $doc:expr, $var:ident => $command:expr) => (
- #[doc = $doc]
- ///
- /// **Positional arguments:**
- /// - Spacing as a size or number, which is interpreted as a multiple
- /// of the font size _(required)_.
- #[derive(Debug, PartialEq)]
- pub struct $ident(Spacing);
-
- function! {
- data: $ident,
-
- parse(args, body, _ctx) {
- parse!(forbidden: body);
-
- let arg = args.get_pos::<ArgExpr>()?;
- let spacing = match arg.val {
- Expression::Size(s) => Spacing::Absolute(*s),
- Expression::Num(f) => Spacing::Relative(*f as f32),
- _ => err!("invalid spacing, expected size or number"),
- };
-
- Ok($ident(spacing))
- }
-
- layout(this, ctx) {
- let $var = match this.0 {
- Spacing::Absolute(s) => s,
- Spacing::Relative(f) => f * ctx.style.font_size,
- };
-
- Ok(commands![$command])
- }
- }
- );
-}
-
-/// Absolute or font-relative spacing.
-#[derive(Debug, PartialEq)]
-enum Spacing {
- Absolute(Size),
- Relative(f32),
-}
-
-spacefunc!(HorizontalSpace, "📖 `h`: Adds horizontal whitespace.",
- space => AddFlex(Layout::empty(space, Size::zero())));
-
-spacefunc!(VerticalSpace, "📑 `v`: Adds vertical whitespace.",
- space => Add(Layout::empty(Size::zero(), space)));
diff --git a/src/library/style.rs b/src/library/style.rs
index 9bcdcccd..90a5fd31 100644
--- a/src/library/style.rs
+++ b/src/library/style.rs
@@ -23,17 +23,17 @@ macro_rules! stylefunc {
Ok(match &this.body {
Some(body) => commands![
- Command::SetStyle(new_style),
- Command::LayoutTree(body),
- Command::SetStyle(ctx.style.clone()),
+ SetStyle(new_style),
+ LayoutTree(body),
+ SetStyle(ctx.style.clone()),
],
- None => commands![Command::SetStyle(new_style)]
+ None => commands![SetStyle(new_style)]
})
}
}
);
}
-stylefunc!(Italic, "💡 `italic`: Sets text in _italics_.");
-stylefunc!(Bold, "🧱 `bold`: Sets text in **bold**.");
-stylefunc!(Monospace, "👩‍💻 `mono`: Sets text in `monospace`.");
+stylefunc!(Italic, "`italic`: Sets text in _italics_.");
+stylefunc!(Bold, "`bold`: Sets text in **bold**.");
+stylefunc!(Monospace, "`mono`: Sets text in `monospace`.");
diff --git a/src/macros.rs b/src/macros.rs
index 70c67105..e7113672 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -57,3 +57,10 @@ macro_rules! debug_display {
}
);
}
+
+macro_rules! pub_use_mod {
+ ($name:ident) => {
+ mod $name;
+ pub use $name::*;
+ };
+}
diff --git a/tests/layouting.rs b/tests/layouting.rs
index 1a406c8c..27999d43 100644
--- a/tests/layouting.rs
+++ b/tests/layouting.rs
@@ -77,7 +77,7 @@ fn test(name: &str, src: &str) {
// Make run warm.
#[cfg(not(debug_assertions))] let warmup_start = Instant::now();
- typesetter.typeset(&src).unwrap();
+ #[cfg(not(debug_assertions))] typesetter.typeset(&src).unwrap();
#[cfg(not(debug_assertions))] let warmup_end = Instant::now();
// Layout into box layout.