diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-10-23 00:14:43 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-10-23 00:21:40 +0200 |
| commit | ecf0ff4d054f11c79ec0ddbbdf45f3dfcf9fc8d7 (patch) | |
| tree | efdc76915e5c7f43629aa3aa5d5aa3998d7f5367 /src/library/structure.rs | |
| parent | cff325b520727ac0eec46a3757831afaa0916cc1 (diff) | |
Introduce a set of macros for writing functions more concisely 🎁
Diffstat (limited to 'src/library/structure.rs')
| -rw-r--r-- | src/library/structure.rs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/library/structure.rs b/src/library/structure.rs new file mode 100644 index 00000000..ae05a12b --- /dev/null +++ b/src/library/structure.rs @@ -0,0 +1,148 @@ +use crate::func::prelude::*; + +/// Ends the current page. +#[derive(Debug, PartialEq)] +pub struct Pagebreak; + +function! { + data: Pagebreak, + parse: plain, + + layout(_, _) { + Ok(commands![Command::FinishLayout]) + } +} + +/// Ends the current line. +#[derive(Debug, PartialEq)] +pub struct Linebreak; + +function! { + data: Linebreak, + parse: plain, + + layout(_, _) { + Ok(commands![Command::FinishFlexRun]) + } +} + +/// 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 alignment = match args.get_ident()? { + "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) => { + Command::AddMany(layout_tree(body, LayoutContext { + alignment: this.alignment, + .. ctx + })?) + } + None => Command::SetAlignment(this.alignment) + }]) + } +} + +/// Layouts content into a box. +#[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_ident_if_present()? { + flow = match ident { + "vertical" => Flow::Vertical, + "horizontal" => Flow::Horizontal, + f => err!("invalid flow specifier: {}", f), + }; + } + args.done()?; + + Ok(Boxed { + body, + flow, + }) + } + + layout(this, ctx) { + Ok(commands![ + Command::AddMany(layout_tree(&this.body, LayoutContext { + flow: this.flow, + .. ctx + })?) + ]) + } +} + +macro_rules! spacefunc { + ($ident:ident, $name:expr, $var:ident => $command:expr) => { + /// Adds whitespace. + #[derive(Debug, PartialEq)] + pub struct $ident(Spacing); + + function! { + data: $ident, + + parse(args, body, _ctx) { + parse!(forbidden: body); + + let spacing = match args.get_expr()? { + Expression::Size(s) => Spacing::Absolute(*s), + Expression::Number(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) => Size::pt(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", space => Command::AddFlex(Layout::empty(space, Size::zero()))); +spacefunc!(VerticalSpace, "v", space => Command::Add(Layout::empty(Size::zero(), space))); |
