summaryrefslogtreecommitdiff
path: root/src/library/structure.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/library/structure.rs')
-rw-r--r--src/library/structure.rs148
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)));