//! The standard library for the _Typst_ language. use crate::func::prelude::*; use toddle::query::FontClass; use keys::*; use maps::*; pub_use_mod!(align); pub_use_mod!(boxed); pub_use_mod!(direction); pub mod maps; pub mod keys; /// Create a scope with all standard functions. pub fn std() -> Scope { let mut std = Scope::new(); std.add::("align"); std.add::("box"); std.add::("direction"); std.add::("page.size"); std.add::("page.margins"); std.add::("n"); std.add::("line.break"); std.add::("par.break"); std.add::("page.break"); std.add::("font.size"); std.add_with_metadata::>("spacing", None); for (name, key) in &[("h", AxisKey::Horizontal), ("v", AxisKey::Vertical)] { std.add_with_metadata::>(name, Some(*key)); } for (name, class) in &[ ("bold", FontClass::Bold), ("italic", FontClass::Italic), ("mono", FontClass::Monospace), ] { std.add_with_metadata::(name, class.clone()); } std } function! { /// `line.break`, `n`: Ends the current line. #[derive(Debug, Default, PartialEq)] pub struct LineBreak; parse(default) layout() { vec![FinishLine] } } function! { /// `par.break`: Ends the current paragraph. /// /// self has the same effect as two subsequent newlines. #[derive(Debug, Default, PartialEq)] pub struct ParBreak; parse(default) layout() { vec![BreakParagraph] } } function! { /// `page.break`: Ends the current page. #[derive(Debug, Default, PartialEq)] pub struct PageBreak; parse(default) layout() { vec![FinishSpace] } } function! { /// `page.size`: Set the size of pages. #[derive(Debug, PartialEq)] pub struct PageSize { map: ExtentMap, } parse(args, body) { parse!(forbidden: body); PageSize { map: ExtentMap::new(&mut args, true)?, } } layout(self, ctx) { let mut style = ctx.style.page; self.map.apply(ctx.axes, &mut style.dimensions, |&s| s)?; vec![SetPageStyle(style)] } } function! { /// `page.margins`: Set the margins of pages. #[derive(Debug, PartialEq)] pub struct PageMargins { map: PaddingMap, } parse(args, body) { parse!(forbidden: body); PageMargins { map: PaddingMap::new(&mut args, true)?, } } layout(self, ctx) { let mut style = ctx.style.page; self.map.apply(ctx.axes, &mut style.margins)?; vec![SetPageStyle(style)] } } function! { /// `spacing`, `h`, `v`: Add spacing along an axis. #[derive(Debug, PartialEq)] pub struct Spacing { axis: AxisKey, spacing: FSize, } type Meta = Option; parse(args, body, _, meta) { let spacing = if let Some(axis) = meta { Spacing { axis, spacing: FSize::from_expr(args.get_pos::()?)?, } } else { if let Some(arg) = args.get_key_next() { let axis = AxisKey::from_ident(&arg.v.key) .map_err(|_| error!(@unexpected_argument))?; let spacing = FSize::from_expr(arg.v.value)?; Spacing { axis, spacing } } else { error!("expected axis and expression") } }; parse!(forbidden: body); spacing } layout(self, ctx) { let axis = self.axis.generic(ctx.axes); let spacing = self.spacing.concretize(ctx.style.text.font_size); vec![AddSpacing(spacing, SpacingKind::Hard, axis)] } } function! { /// `bold`, `italic`, `mono`: Sets text with a different style. #[derive(Debug, PartialEq)] pub struct StyleChange { body: Option, class: FontClass, } type Meta = FontClass; parse(args, body, ctx, meta) { StyleChange { body: parse!(optional: body, ctx), class: meta, } } layout(self, ctx) { let mut style = ctx.style.text.clone(); style.toggle_class(self.class.clone()); match &self.body { Some(body) => vec![ SetTextStyle(style), LayoutTree(body), SetTextStyle(ctx.style.text.clone()), ], None => vec![SetTextStyle(style)] } } } function! { /// `font.size`: Set the font size. #[derive(Debug, PartialEq)] pub struct FontSize { body: Option, size: Size, } parse(args, body, ctx) { FontSize { body: parse!(optional: body, ctx), size: args.get_pos::()?.v, } } layout(self, mut ctx) { let mut style = ctx.style.text.clone(); style.font_size = self.size; match &self.body { Some(body) => vec![ SetTextStyle(style), LayoutTree(body), SetTextStyle(ctx.style.text.clone()), ], None => vec![SetTextStyle(style)] } } }