diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/align.rs | 7 | ||||
| -rw-r--r-- | src/library/boxed.rs | 5 | ||||
| -rw-r--r-- | src/library/direction.rs | 5 | ||||
| -rw-r--r-- | src/library/mod.rs | 400 |
4 files changed, 216 insertions, 201 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index 524ada61..03d905cd 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -1,16 +1,17 @@ use crate::func::prelude::*; use super::maps::{PosAxisMap, AlignmentKey}; + function! { /// `align`: Aligns content along the layouting axes. #[derive(Debug, PartialEq)] - pub struct Align { + pub struct AlignFunc { body: Option<SyntaxTree>, map: PosAxisMap<AlignmentKey>, } parse(args, body, ctx) { - Align { + AlignFunc { body: parse!(optional: body, ctx), map: PosAxisMap::new(&mut args)?, } @@ -28,7 +29,7 @@ function! { match &self.body { Some(body) => vec![AddMultiple(layout(&body, ctx)?)], - None => vec![Command::SetAlignment(ctx.alignment)], + None => vec![SetAlignment(ctx.alignment)], } } } diff --git a/src/library/boxed.rs b/src/library/boxed.rs index 7333c50f..a4d059cb 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -3,17 +3,18 @@ use smallvec::smallvec; use crate::func::prelude::*; use super::maps::ExtentMap; + function! { /// `box`: Layouts content into a box. #[derive(Debug, PartialEq)] - pub struct Boxed { + pub struct BoxFunc { body: SyntaxTree, map: ExtentMap<PSize>, debug: Option<bool>, } parse(args, body, ctx) { - Boxed { + BoxFunc { body: parse!(optional: body, ctx).unwrap_or(SyntaxTree::new()), map: ExtentMap::new(&mut args, false)?, debug: args.get_key_opt::<bool>("debug")?, diff --git a/src/library/direction.rs b/src/library/direction.rs index 7bb11c99..a0992075 100644 --- a/src/library/direction.rs +++ b/src/library/direction.rs @@ -1,16 +1,17 @@ use crate::func::prelude::*; use super::maps::PosAxisMap; + function! { /// `direction`: Sets the directions of the layouting axes. #[derive(Debug, PartialEq)] - pub struct DirectionChange { + pub struct DirectionFunc { body: Option<SyntaxTree>, map: PosAxisMap<Direction>, } parse(args, body, ctx) { - DirectionChange { + DirectionFunc { body: parse!(optional: body, ctx), map: PosAxisMap::new(&mut args)?, } diff --git a/src/library/mod.rs b/src/library/mod.rs index d4519867..ac1ac338 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -12,73 +12,168 @@ pub_use_mod!(align); pub_use_mod!(boxed); pub_use_mod!(direction); + /// 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::<DirectionChange>("direction"); - - std.add::<LineBreak>("n"); - std.add::<LineBreak>("line.break"); - std.add::<ParBreak>("par.break"); - std.add::<PageBreak>("page.break"); + // Font setup + std.add::<FontFamilyFunc>("font.family"); + std.add::<FontStyleFunc>("font.style"); + std.add::<FontWeightFunc>("font.weight"); + std.add::<FontSizeFunc>("font.size"); + + // Layout + std.add::<AlignFunc>("align"); + std.add::<DirectionFunc>("direction"); + std.add_with_metadata::<ContentSpacingFunc>("par.spacing", ContentKind::Paragraph); + std.add_with_metadata::<ContentSpacingFunc>("word.spacing", ContentKind::Word); + std.add_with_metadata::<ContentSpacingFunc>("line.spacing", ContentKind::Line); + std.add::<BoxFunc>("box"); + + // Spacing + std.add::<LineBreakFunc>("n"); + std.add::<LineBreakFunc>("line.break"); + std.add::<ParBreakFunc>("par.break"); + std.add::<PageBreakFunc>("page.break"); + std.add_with_metadata::<SpacingFunc>("spacing", None); + std.add_with_metadata::<SpacingFunc>("h", Some(Horizontal)); + std.add_with_metadata::<SpacingFunc>("v", Some(Vertical)); + + // Page setup + std.add::<PageSizeFunc>("page.size"); + std.add::<PageMarginsFunc>("page.margins"); - std.add_with_metadata::<ContentSpacing>("word.spacing", ContentKind::Word); - std.add_with_metadata::<ContentSpacing>("line.spacing", ContentKind::Line); - std.add_with_metadata::<ContentSpacing>("par.spacing", ContentKind::Paragraph); + std +} - std.add::<PageSize>("page.size"); - std.add::<PageMargins>("page.margins"); +// -------------------------------------------------------------------------- // +// Font setup - std.add_with_metadata::<Spacing>("spacing", None); - std.add_with_metadata::<Spacing>("h", Some(Horizontal)); - std.add_with_metadata::<Spacing>("v", Some(Vertical)); +function! { + /// `font.family`: Set the font family. + #[derive(Debug, PartialEq)] + pub struct FontFamilyFunc { + body: Option<SyntaxTree>, + family: String, + } - std.add_with_metadata::<FontFamily>("font.family", None); - std.add_with_metadata::<FontFamily>("mono", Some("monospace".to_string())); - std.add::<SetFontStyle>("font.style"); - std.add::<SetFontWeight>("font.weight"); - std.add::<FontSize>("font.size"); + parse(args, body, ctx, meta) { + FontFamilyFunc { + body: parse!(optional: body, ctx), + family: args.get_pos::<String>()?, + } + } - std + layout(self, ctx) { + let mut style = ctx.style.text.clone(); + style.fallback.list = vec![self.family.clone()]; + styled(&self.body, &ctx, style) + } } function! { - /// `line.break`, `n`: Ends the current line. - #[derive(Debug, Default, PartialEq)] - pub struct LineBreak; + /// `font.style`: Set the font style (normal / italic). + #[derive(Debug, PartialEq)] + pub struct FontStyleFunc { + body: Option<SyntaxTree>, + style: FontStyle, + } - parse(default) - layout() { vec![FinishLine] } + parse(args, body, ctx) { + FontStyleFunc { + body: parse!(optional: body, ctx), + style: { + let s = args.get_pos::<String>()?; + match FontStyle::from_str(&s) { + Some(style) => style, + None => error!("invalid font style: `{}`", s), + } + } + } + } + + layout(self, ctx) { + let mut style = ctx.style.text.clone(); + style.variant.style = self.style; + styled(&self.body, &ctx, style) + } } function! { - /// `par.break`: Ends the current paragraph. - /// - /// self has the same effect as two subsequent newlines. - #[derive(Debug, Default, PartialEq)] - pub struct ParBreak; + /// `font.weight`: Set text with a given weight. + #[derive(Debug, PartialEq)] + pub struct FontWeightFunc { + body: Option<SyntaxTree>, + weight: FontWeight, + } - parse(default) - layout() { vec![BreakParagraph] } + parse(args, body, ctx, meta) { + FontWeightFunc { + body: parse!(optional: body, ctx), + weight: match args.get_pos::<Expression>()? { + Expression::Num(weight) => { + let weight = weight.round() as i16; + FontWeight( + if weight < 100 { 100 } + else if weight <= 900 { weight } + else { 900 } + ) + } + Expression::Ident(Ident(s)) => { + match FontWeight::from_str(&s) { + Some(weight) => weight, + None => error!("invalid font weight: `{}`", s), + } + } + _ => error!("expected identifier or number"), + }, + } + } + + layout(self, ctx) { + let mut style = ctx.style.text.clone(); + style.variant.style.toggle(); + styled(&self.body, &ctx, style) + } } function! { - /// `page.break`: Ends the current page. - #[derive(Debug, Default, PartialEq)] - pub struct PageBreak; + /// `font.size`: Sets the font size. + #[derive(Debug, PartialEq)] + pub struct FontSizeFunc { + body: Option<SyntaxTree>, + size: ScaleSize, + } - parse(default) - layout() { vec![BreakPage] } + parse(args, body, ctx) { + FontSizeFunc { + body: parse!(optional: body, ctx), + size: args.get_pos::<ScaleSize>()?, + } + } + + layout(self, ctx) { + let mut style = ctx.style.text.clone(); + match self.size { + ScaleSize::Absolute(size) => { + style.base_font_size = size; + style.font_scale = 1.0; + } + ScaleSize::Scaled(scale) => style.font_scale = scale, + } + styled(&self.body, &ctx, style) + } } +// -------------------------------------------------------------------------- // +// Layout + function! { /// `word.spacing`, `line.spacing`, `par.spacing`: The spacing between /// words, lines or paragraphs as a multiple of the font size. #[derive(Debug, PartialEq)] - pub struct ContentSpacing { + pub struct ContentSpacingFunc { body: Option<SyntaxTree>, content: ContentKind, spacing: f32, @@ -87,7 +182,7 @@ function! { type Meta = ContentKind; parse(args, body, ctx, meta) { - ContentSpacing { + ContentSpacingFunc { body: parse!(optional: body, ctx), content: meta, spacing: args.get_pos::<f64>()? as f32, @@ -113,77 +208,42 @@ pub enum ContentKind { Paragraph, } -function! { - /// `page.size`: Set the size of pages. - #[derive(Debug, PartialEq)] - pub enum PageSize { - Paper(Paper, bool), - Custom(ExtentMap<PSize>), - } +// -------------------------------------------------------------------------- // +// Spacing - parse(args, body) { - parse!(forbidden: body); - - if let Some(name) = args.get_pos_opt::<Ident>()? { - let landscape = args.get_key_opt::<bool>("landscape")? - .unwrap_or(false); - PageSize::Paper(Paper::from_name(name.as_str())?, landscape) - } else { - PageSize::Custom(ExtentMap::new(&mut args, true)?) - } - } - - layout(self, ctx) { - let mut style = ctx.style.page; - - match self { - PageSize::Paper(paper, landscape) => { - style.class = paper.class; - style.dimensions = paper.dimensions; - if *landscape { - style.dimensions.swap(); - } - } +function! { + /// `line.break`, `n`: Ends the current line. + #[derive(Debug, Default, PartialEq)] + pub struct LineBreakFunc; - PageSize::Custom(map) => { - style.class = PaperClass::Custom; + parse(default) + layout() { vec![FinishLine] } +} - let map = map.dedup(ctx.axes)?; - let dims = &mut style.dimensions; - map.with(Horizontal, |&psize| dims.x = psize.scaled(dims.x)); - map.with(Vertical, |&psize| dims.y = psize.scaled(dims.y)); - } - } +function! { + /// `par.break`: Ends the current paragraph. + /// + /// self has the same effect as two subsequent newlines. + #[derive(Debug, Default, PartialEq)] + pub struct ParBreakFunc; - vec![SetPageStyle(style)] - } + parse(default) + layout() { vec![BreakParagraph] } } function! { - /// `page.margins`: Sets the page margins. - #[derive(Debug, PartialEq)] - pub struct PageMargins { - map: PaddingMap, - } - - parse(args, body) { - parse!(forbidden: body); - PageMargins { - map: PaddingMap::new(&mut args)?, - } - } + /// `page.break`: Ends the current page. + #[derive(Debug, Default, PartialEq)] + pub struct PageBreakFunc; - layout(self, ctx) { - let mut style = ctx.style.page; - self.map.apply(ctx.axes, &mut style.margins)?; - vec![SetPageStyle(style)] - } + parse(default) + layout() { vec![BreakPage] } } function! { /// `spacing`, `h`, `v`: Adds spacing along an axis. #[derive(Debug, PartialEq)] - pub struct Spacing { + pub struct SpacingFunc { axis: AxisKey, spacing: FSize, } @@ -194,7 +254,7 @@ function! { parse!(forbidden: body); if let Some(axis) = meta { - Spacing { + SpacingFunc { axis: AxisKey::Specific(axis), spacing: FSize::from_expr(args.get_pos::<Spanned<Expression>>()?)?, } @@ -203,7 +263,7 @@ function! { .map_err(|_| error!(@unexpected_argument))?; let spacing = FSize::from_expr(arg.v.value)?; - Spacing { axis, spacing } + SpacingFunc { axis, spacing } } else { error!("expected axis and spacing") } @@ -212,131 +272,83 @@ function! { layout(self, ctx) { let axis = self.axis.to_generic(ctx.axes); let spacing = self.spacing.scaled(ctx.style.text.font_size()); - vec![AddSpacing(spacing, SpacingKind::Hard, axis)] + vec![SpacingFunc(spacing, SpacingKind::Hard, axis)] } } +// -------------------------------------------------------------------------- // +// Page setup + function! { - /// `font.weight`, `bold`: Set text with a given weight. + /// `page.size`: Set the size of pages. #[derive(Debug, PartialEq)] - pub struct SetFontWeight { - body: Option<SyntaxTree>, - weight: FontWeight, + pub enum PageSizeFunc { + Paper(Paper, bool), + Custom(ExtentMap<PSize>), } - parse(args, body, ctx, meta) { - SetFontWeight { - body: parse!(optional: body, ctx), - weight: match args.get_pos::<Expression>()? { - Expression::Num(weight) => FontWeight(if weight < 0.0 { - 0 - } else if weight < 1000.0 { - weight.round() as u16 - } else { - 1000 - }), - Expression::Ident(Ident(s)) => { - match FontWeight::from_str(&s) { - Some(weight) => weight, - None => error!("invalid font weight: `{}`", s), - } - } - _ => error!("expected identifier or number"), - }, + parse(args, body) { + parse!(forbidden: body); + + if let Some(name) = args.get_pos_opt::<Ident>()? { + let flip = args.get_key_opt::<bool>("flip")? + .unwrap_or(false); + PageSizeFunc::Paper(Paper::from_name(name.as_str())?, flip) + } else { + PageSizeFunc::Custom(ExtentMap::new(&mut args, true)?) } } layout(self, ctx) { - let mut style = ctx.style.text.clone(); - style.variant.style.toggle(); - styled(&self.body, &ctx, style) - } -} - -function! { - /// `font.style`: Set the font style (normal / italic). - #[derive(Debug, PartialEq)] - pub struct SetFontStyle { - body: Option<SyntaxTree>, - style: FontStyle, - } + let mut style = ctx.style.page; - parse(args, body, ctx) { - SetFontStyle { - body: parse!(optional: body, ctx), - style: { - let s = args.get_pos::<String>()?; - match FontStyle::from_str(&s) { - Some(style) => style, - None => error!("invalid font style: `{}`", s), + match self { + PageSizeFunc::Paper(paper, flip) => { + style.class = paper.class; + style.dimensions = paper.dimensions; + if *flip { + style.dimensions.swap(); } } - } - } - - layout(self, ctx) { - let mut style = ctx.style.text.clone(); - style.variant.style = self.style; - styled(&self.body, &ctx, style) - } -} -function! { - /// `font.family`: Set the font family. - #[derive(Debug, PartialEq)] - pub struct FontFamily { - body: Option<SyntaxTree>, - family: String, - } - - type Meta = Option<String>; + PageSizeFunc::Custom(map) => { + style.class = PaperClass::Custom; - parse(args, body, ctx, meta) { - FontFamily { - body: parse!(optional: body, ctx), - family: if let Some(family) = meta { - family - } else { - args.get_pos::<String>()? - }, + let map = map.dedup(ctx.axes)?; + let dims = &mut style.dimensions; + map.with(Horizontal, |&psize| dims.x = psize.scaled(dims.x)); + map.with(Vertical, |&psize| dims.y = psize.scaled(dims.y)); + } } - } - layout(self, ctx) { - let mut style = ctx.style.text.clone(); - style.fallback.list = vec![self.family.clone()]; - styled(&self.body, &ctx, style) + vec![SetPageStyle(style)] } } function! { - /// `font.size`: Sets the font size. + /// `page.margins`: Sets the page margins. #[derive(Debug, PartialEq)] - pub struct FontSize { - body: Option<SyntaxTree>, - size: ScaleSize, + pub struct PageMarginsFunc { + map: PaddingMap, } - parse(args, body, ctx) { - FontSize { - body: parse!(optional: body, ctx), - size: args.get_pos::<ScaleSize>()?, + parse(args, body) { + parse!(forbidden: body); + PageMarginsFunc { + map: PaddingMap::new(&mut args)?, } } layout(self, ctx) { - let mut style = ctx.style.text.clone(); - match self.size { - ScaleSize::Absolute(size) => { - style.base_font_size = size; - style.font_scale = 1.0; - } - ScaleSize::Scaled(scale) => style.font_scale = scale, - } - styled(&self.body, &ctx, style) + let mut style = ctx.style.page; + self.map.apply(ctx.axes, &mut style.margins)?; + vec![SetPageStyle(style)] } } +// -------------------------------------------------------------------------- // +// Helpers + /// Layout the body with the style or update the style if there is no body. fn styled<'a>( body: &'a Option<SyntaxTree>, |
