diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-06-22 12:25:01 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-06-22 12:25:01 +0200 |
| commit | f6fe3b5cdd2805f3975985752f9cb0e04e3daf49 (patch) | |
| tree | daddf46ba6add0b7cead1f9015b8f24364672138 /src/func.rs | |
| parent | e39a6efccff7ba2b5dd546ddf86f23d2714161e7 (diff) | |
Implement function layouting ✒
Diffstat (limited to 'src/func.rs')
| -rw-r--r-- | src/func.rs | 68 |
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 } +} |
