summaryrefslogtreecommitdiff
path: root/src/func.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-06-22 12:25:01 +0200
committerLaurenz <laurmaedje@gmail.com>2019-06-22 12:25:01 +0200
commitf6fe3b5cdd2805f3975985752f9cb0e04e3daf49 (patch)
treedaddf46ba6add0b7cead1f9015b8f24364672138 /src/func.rs
parente39a6efccff7ba2b5dd546ddf86f23d2714161e7 (diff)
Implement function layouting ✒
Diffstat (limited to 'src/func.rs')
-rw-r--r--src/func.rs68
1 files changed, 61 insertions, 7 deletions
diff --git a/src/func.rs b/src/func.rs
index 402bf6fa..0d2a6274 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -4,9 +4,10 @@ use std::any::Any;
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
-use crate::layout::{Layout, LayoutContext, LayoutResult};
-use crate::parsing::{ParseContext, ParseResult};
-use crate::syntax::FuncHeader;
+use crate::layout::{layout, Layout, LayoutContext, LayoutResult};
+use crate::layout::flex::FlexLayout;
+use crate::parsing::{parse, ParseContext, ParseError, ParseResult};
+use crate::syntax::{SyntaxTree, FuncHeader};
/// Typesetting function types.
@@ -25,8 +26,7 @@ pub trait Function: FunctionBounds {
///
/// Returns optionally the resulting layout and a new context if changes to the context should
/// be made.
- fn layout(&self, ctx: &LayoutContext)
- -> LayoutResult<(Option<Layout>, Option<LayoutContext>)>;
+ fn layout(&self, ctx: &LayoutContext) -> LayoutResult<Option<Layout>>;
}
impl PartialEq for dyn Function {
@@ -76,9 +76,14 @@ impl Scope {
Scope { parsers: HashMap::new() }
}
- /// Create a new scope with the standard functions contained.
+ /// Create a new scope with the standard functions contained:
+ /// - `italic`
+ /// - `bold`
pub fn with_std() -> Scope {
- Scope::new()
+ let mut std = Scope::new();
+ std.add::<BoldFunc>("bold");
+ std.add::<ItalicFunc>("italic");
+ std
}
/// Add a function type to the scope giving it a name.
@@ -103,3 +108,52 @@ impl Debug for Scope {
write!(f, "{:?}", self.parsers.keys())
}
}
+
+/// Creates style functions like bold and italic.
+macro_rules! style_func {
+ ($(#[$outer:meta])* pub struct $struct:ident { $name:expr },
+ $new_ctx:ident => $ctx_change:block) => {
+ $(#[$outer])*
+ #[derive(Debug, PartialEq)]
+ pub struct $struct { body: SyntaxTree }
+ impl Function for $struct {
+ fn parse(header: &FuncHeader, body: Option<&str>, ctx: &ParseContext)
+ -> ParseResult<Self> where Self: Sized {
+ // Accept only invocations without arguments and with body.
+ if header.args.is_empty() && header.kwargs.is_empty() {
+ if let Some(body) = body {
+ Ok($struct { body: parse(body, ctx)? })
+ } else {
+ Err(ParseError::new(format!("expected body for function `{}`", $name)))
+ }
+ } else {
+ Err(ParseError::new(format!("unexpected arguments to function `{}`", $name)))
+ }
+ }
+
+ fn layout(&self, ctx: &LayoutContext) -> LayoutResult<Option<Layout>> {
+ // Change the context.
+ let mut $new_ctx = ctx.clone();
+ $ctx_change
+
+ // Create a box and put it into a flex layout.
+ let boxed = layout(&self.body, &$new_ctx)?;
+ let flex = FlexLayout::from_box(boxed);
+
+ Ok(Some(Layout::Flex(flex)))
+ }
+ }
+ };
+}
+
+style_func! {
+ /// Typesets text in bold.
+ pub struct BoldFunc { "bold" },
+ ctx => { ctx.style.bold = !ctx.style.bold }
+}
+
+style_func! {
+ /// Typesets text in italics.
+ pub struct ItalicFunc { "italic" },
+ ctx => { ctx.style.italic = !ctx.style.italic }
+}