diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/align.rs | 94 | ||||
| -rw-r--r-- | src/library/boxed.rs | 60 | ||||
| -rw-r--r-- | src/library/font.rs | 110 | ||||
| -rw-r--r-- | src/library/mod.rs | 62 | ||||
| -rw-r--r-- | src/library/page.rs | 94 | ||||
| -rw-r--r-- | src/library/spacing.rs | 46 | ||||
| -rw-r--r-- | src/library/val.rs | 28 |
7 files changed, 199 insertions, 295 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index b4cfd2e2..c716faef 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -10,67 +10,49 @@ use super::*; /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub fn align(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { +pub async fn align(mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> { let mut f = Feedback::new(); - let mut args = call.args; - let node = AlignNode { - content: args.take::<SyntaxTree>(), - aligns: args.take_all_num_vals::<Spanned<SpecAlign>>().collect(), - h: args.take_with_key::<_, Spanned<SpecAlign>>("horizontal", &mut f), - v: args.take_with_key::<_, Spanned<SpecAlign>>("vertical", &mut f), - }; - args.unexpected(&mut f); - Pass::node(node, f) -} - -#[derive(Debug, Clone, PartialEq)] -struct AlignNode { - content: Option<SyntaxTree>, - aligns: SpanVec<SpecAlign>, - h: Option<Spanned<SpecAlign>>, - v: Option<Spanned<SpecAlign>>, -} -#[async_trait(?Send)] -impl Layout for AlignNode { - async fn layout<'a>(&'a self, mut ctx: LayoutContext<'_>) -> Pass<Commands<'a>> { - let mut f = Feedback::new(); + let content = args.take::<SyntaxTree>(); + let aligns: Vec<_> = args.take_all_num_vals::<Spanned<SpecAlign>>().collect(); + let h = args.take_with_key::<_, Spanned<SpecAlign>>("horizontal", &mut f); + let v = args.take_with_key::<_, Spanned<SpecAlign>>("vertical", &mut f); + args.unexpected(&mut f); - ctx.base = ctx.spaces[0].size; + ctx.base = ctx.spaces[0].size; - let axes = ctx.axes; - let all = self.aligns.iter() - .map(|align| { - let spec = align.v.axis().unwrap_or(axes.primary.axis()); - (spec, align) - }) - .chain(self.h.iter().map(|align| (Horizontal, align))) - .chain(self.v.iter().map(|align| (Vertical, align))); + let axes = ctx.axes; + let all = aligns.iter() + .map(|align| { + let spec = align.v.axis().unwrap_or(axes.primary.axis()); + (spec, align) + }) + .chain(h.iter().map(|align| (Horizontal, align))) + .chain(v.iter().map(|align| (Vertical, align))); - let mut had = [false; 2]; - for (axis, align) in all { - if align.v.axis().map(|a| a != axis).unwrap_or(false) { - error!( - @f, align.span, - "invalid alignment {} for {} axis", align.v, axis, - ); - } else if had[axis as usize] { - error!(@f, align.span, "duplicate alignment for {} axis", axis); - } else { - had[axis as usize] = true; - let gen_axis = axis.to_generic(ctx.axes); - let gen_align = align.v.to_generic(ctx.axes); - *ctx.align.get_mut(gen_axis) = gen_align; - } + let mut had = [false; 2]; + for (axis, align) in all { + if align.v.axis().map(|a| a != axis).unwrap_or(false) { + error!( + @f, align.span, + "invalid alignment {} for {} axis", align.v, axis, + ); + } else if had[axis as usize] { + error!(@f, align.span, "duplicate alignment for {} axis", axis); + } else { + had[axis as usize] = true; + let gen_axis = axis.to_generic(ctx.axes); + let gen_align = align.v.to_generic(ctx.axes); + *ctx.align.get_mut(gen_axis) = gen_align; } - - Pass::new(match &self.content { - Some(tree) => { - let layouted = layout(tree, ctx).await; - f.extend(layouted.feedback); - vec![AddMultiple(layouted.output)] - } - None => vec![SetAlignment(ctx.align)], - }, f) } + + Pass::commands(match content { + Some(tree) => { + let layouted = layout(&tree, ctx).await; + f.extend(layouted.feedback); + vec![AddMultiple(layouted.output)] + } + None => vec![SetAlignment(ctx.align)], + }, f) } diff --git a/src/library/boxed.rs b/src/library/boxed.rs index 3637f072..c03043ae 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -6,48 +6,32 @@ use super::*; /// # Keyword arguments /// - `width`: The width of the box (length of relative to parent's width). /// - `height`: The height of the box (length of relative to parent's height). -pub fn boxed(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { +pub async fn boxed(mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> { let mut f = Feedback::new(); - let mut args = call.args; - let node = BoxNode { - content: args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new()), - width: args.take_with_key::<_, ScaleLength>("width", &mut f), - height: args.take_with_key::<_, ScaleLength>("height", &mut f), - }; + let content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new()); + let width = args.take_with_key::<_, ScaleLength>("width", &mut f); + let height = args.take_with_key::<_, ScaleLength>("height", &mut f); args.unexpected(&mut f); - Pass::node(node, f) -} - -#[derive(Debug, Clone, PartialEq)] -struct BoxNode { - content: SyntaxTree, - width: Option<ScaleLength>, - height: Option<ScaleLength>, -} -#[async_trait(?Send)] -impl Layout for BoxNode { - async fn layout<'a>(&'a self, mut ctx: LayoutContext<'_>) -> Pass<Commands<'a>> { - ctx.spaces.truncate(1); - ctx.repeat = false; + ctx.spaces.truncate(1); + ctx.repeat = false; - self.width.with(|v| { - let length = v.raw_scaled(ctx.base.x); - ctx.base.x = length; - ctx.spaces[0].size.x = length; - ctx.spaces[0].expansion.horizontal = true; - }); + width.with(|v| { + let length = v.raw_scaled(ctx.base.x); + ctx.base.x = length; + ctx.spaces[0].size.x = length; + ctx.spaces[0].expansion.horizontal = true; + }); - self.height.with(|v| { - let length = v.raw_scaled(ctx.base.y); - ctx.base.y = length; - ctx.spaces[0].size.y = length; - ctx.spaces[0].expansion.vertical = true; - }); + height.with(|v| { + let length = v.raw_scaled(ctx.base.y); + ctx.base.y = length; + ctx.spaces[0].size.y = length; + ctx.spaces[0].expansion.vertical = true; + }); - layout(&self.content, ctx).await.map(|out| { - let layout = out.into_iter().next().unwrap(); - vec![Add(layout)] - }) - } + let layouted = layout(&content, ctx).await; + let layout = layouted.output.into_iter().next().unwrap(); + f.extend(layouted.feedback); + Pass::commands(vec![Add(layout)], f) } diff --git a/src/library/font.rs b/src/library/font.rs index 8787cc91..71e9552f 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -18,80 +18,60 @@ use super::*; /// ```typst /// serif = ("Source Serif Pro", "Noto Serif") /// ``` -pub fn font(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { +pub async fn font(mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> { let mut f = Feedback::new(); - let mut args = call.args; - let node = FontNode { - content: args.take::<SyntaxTree>(), - size: args.take::<ScaleLength>(), - style: args.take_with_key::<_, FontStyle>("style", &mut f), - weight: args.take_with_key::<_, FontWeight>("weight", &mut f), - width: args.take_with_key::<_, FontWidth>("width", &mut f), - list: args.take_all_num_vals::<StringLike>() - .map(|s| s.0.to_lowercase()) - .collect(), - classes: args.take_all_str::<TableExpr>() - .map(|(class, mut table)| { - let fallback = table.take_all_num_vals::<StringLike>() - .map(|s| s.0.to_lowercase()) - .collect(); - (class, fallback) - }) - .collect() - }; + let content = args.take::<SyntaxTree>(); + let size = args.take::<ScaleLength>(); + let style = args.take_with_key::<_, FontStyle>("style", &mut f); + let weight = args.take_with_key::<_, FontWeight>("weight", &mut f); + let width = args.take_with_key::<_, FontWidth>("width", &mut f); + let list: Vec<_> = args.take_all_num_vals::<StringLike>() + .map(|s| s.0.to_lowercase()) + .collect(); + let classes: Vec<(_, Vec<_>)> = args.take_all_str::<TableValue>() + .map(|(class, mut table)| { + let fallback = table.take_all_num_vals::<StringLike>() + .map(|s| s.0.to_lowercase()) + .collect(); + (class, fallback) + }) + .collect(); args.unexpected(&mut f); - Pass::node(node, f) -} - -#[derive(Debug, Clone, PartialEq)] -struct FontNode { - content: Option<SyntaxTree>, - size: Option<ScaleLength>, - style: Option<FontStyle>, - weight: Option<FontWeight>, - width: Option<FontWidth>, - list: Vec<String>, - classes: Vec<(String, Vec<String>)>, -} - -#[async_trait(?Send)] -impl Layout for FontNode { - async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass<Commands<'a>> { - let mut text = ctx.style.text.clone(); - - self.size.with(|s| match s { - ScaleLength::Absolute(length) => { - text.base_font_size = length.as_raw(); - text.font_scale = 1.0; - } - ScaleLength::Scaled(scale) => text.font_scale = scale, - }); - self.style.with(|s| text.variant.style = s); - self.weight.with(|w| text.variant.weight = w); - self.width.with(|w| text.variant.width = w); + let mut text = ctx.style.text.clone(); - if !self.list.is_empty() { - *text.fallback.list_mut() = self.list.iter() - .map(|s| s.to_lowercase()) - .collect(); + size.with(|s| match s { + ScaleLength::Absolute(length) => { + text.base_font_size = length.as_raw(); + text.font_scale = 1.0; } + ScaleLength::Scaled(scale) => text.font_scale = scale, + }); - for (class, fallback) in &self.classes { - text.fallback.set_class_list(class.clone(), fallback.clone()); - } + style.with(|s| text.variant.style = s); + weight.with(|w| text.variant.weight = w); + width.with(|w| text.variant.width = w); - text.fallback.flatten(); + if !list.is_empty() { + *text.fallback.list_mut() = list.iter() + .map(|s| s.to_lowercase()) + .collect(); + } - Pass::okay(match &self.content { - Some(tree) => vec![ - SetTextStyle(text), - LayoutSyntaxTree(tree), - SetTextStyle(ctx.style.text.clone()), - ], - None => vec![SetTextStyle(text)], - }) + for (class, fallback) in classes { + text.fallback.set_class_list(class.clone(), fallback.clone()); } + + text.fallback.flatten(); + + Pass::commands(match content { + Some(tree) => vec![ + SetTextStyle(text), + LayoutSyntaxTree(tree), + SetTextStyle(ctx.style.text.clone()), + ], + None => vec![SetTextStyle(text)], + }, f) } diff --git a/src/library/mod.rs b/src/library/mod.rs index ef24d74f..1999ba31 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -5,30 +5,60 @@ mod boxed; mod font; mod page; mod spacing; -mod val; pub use align::*; pub use boxed::*; pub use font::*; pub use page::*; pub use spacing::*; -pub use val::*; -use crate::func::prelude::*; -use crate::syntax::scope::Scope; +use std::rc::Rc; -/// Create a scope with all standard library functions. -pub fn _std() -> Scope { - let mut std = Scope::new(Box::new(val)); +use crate::compute::scope::Scope; +use crate::prelude::*; - std.insert("val", Box::new(val)); - std.insert("font", Box::new(font)); - std.insert("page", Box::new(page)); - std.insert("align", Box::new(align)); - std.insert("box", Box::new(boxed)); - std.insert("pagebreak", Box::new(pagebreak)); - std.insert("h", Box::new(h)); - std.insert("v", Box::new(v)); +macro_rules! std { + (fallback: $fallback:expr $(, $name:literal => $func:expr)* $(,)?) => { + /// Create a scope with all standard library functions. + pub fn _std() -> Scope { + let mut std = Scope::new(wrap!(val)); + $(std.insert($name, wrap!($func));)* + std + } + }; +} + +macro_rules! wrap { + ($func:expr) => { + Rc::new(|args, ctx| Box::pin($func(args, ctx))) + }; +} + +std! { + fallback: val, + "align" => align, + "box" => boxed, + "dump" => dump, + "font" => font, + "h" => h, + "page" => page, + "pagebreak" => pagebreak, + "v" => v, + "val" => val, +} + +/// `val`: Layouts its body flatly, ignoring other arguments. +/// +/// This is also the fallback function, which is used when a function name +/// cannot be resolved. +pub async fn val(mut args: TableValue, _: LayoutContext<'_>) -> Pass<Value> { + Pass::commands(match args.take::<SyntaxTree>() { + Some(tree) => vec![LayoutSyntaxTree(tree)], + None => vec![], + }, Feedback::new()) +} - std +/// `dump`: Dumps its arguments. +pub async fn dump(args: TableValue, _: LayoutContext<'_>) -> Pass<Value> { + Pass::okay(Value::Table(args)) } diff --git a/src/library/page.rs b/src/library/page.rs index 7e4e6e54..42f29dbb 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -16,78 +16,46 @@ use super::*; /// - `top`: The top margin (length or relative to height). /// - `bottom`: The bottom margin (length or relative to height). /// - `flip`: Flips custom or paper-defined width and height (boolean). -pub fn page(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { +pub async fn page(mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> { let mut f = Feedback::new(); - let mut args = call.args; - let node = PageNode { - paper: args.take::<Paper>(), - width: args.take_with_key::<_, Length>("width", &mut f), - height: args.take_with_key::<_, Length>("height", &mut f), - margins: args.take_with_key::<_, ScaleLength>("margins", &mut f), - left: args.take_with_key::<_, ScaleLength>("left", &mut f), - right: args.take_with_key::<_, ScaleLength>("right", &mut f), - top: args.take_with_key::<_, ScaleLength>("top", &mut f), - bottom: args.take_with_key::<_, ScaleLength>("bottom", &mut f), - flip: args.take_with_key::<_, bool>("flip", &mut f).unwrap_or(false), - }; + let paper = args.take::<Paper>(); + let width = args.take_with_key::<_, Length>("width", &mut f); + let height = args.take_with_key::<_, Length>("height", &mut f); + let margins = args.take_with_key::<_, ScaleLength>("margins", &mut f); + let left = args.take_with_key::<_, ScaleLength>("left", &mut f); + let right = args.take_with_key::<_, ScaleLength>("right", &mut f); + let top = args.take_with_key::<_, ScaleLength>("top", &mut f); + let bottom = args.take_with_key::<_, ScaleLength>("bottom", &mut f); + let flip = args.take_with_key::<_, bool>("flip", &mut f).unwrap_or(false); args.unexpected(&mut f); - Pass::node(node, f) -} - -#[derive(Debug, Clone, PartialEq)] -struct PageNode { - paper: Option<Paper>, - width: Option<Length>, - height: Option<Length>, - margins: Option<ScaleLength>, - left: Option<ScaleLength>, - right: Option<ScaleLength>, - top: Option<ScaleLength>, - bottom: Option<ScaleLength>, - flip: bool, -} -#[async_trait(?Send)] -impl Layout for PageNode { - async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass<Commands<'a>> { - let mut style = ctx.style.page; + let mut style = ctx.style.page; - if let Some(paper) = self.paper { - style.class = paper.class; - style.size = paper.size(); - } else if self.width.is_some() || self.height.is_some() { - style.class = PaperClass::Custom; - } - - self.width.with(|v| style.size.x = v.as_raw()); - self.height.with(|v| style.size.y = v.as_raw()); - self.margins.with(|v| style.margins.set_all(Some(v))); - self.left.with(|v| style.margins.left = Some(v)); - self.right.with(|v| style.margins.right = Some(v)); - self.top.with(|v| style.margins.top = Some(v)); - self.bottom.with(|v| style.margins.bottom = Some(v)); + if let Some(paper) = paper { + style.class = paper.class; + style.size = paper.size(); + } else if width.is_some() || height.is_some() { + style.class = PaperClass::Custom; + } - if self.flip { - style.size.swap(); - } + width.with(|v| style.size.x = v.as_raw()); + height.with(|v| style.size.y = v.as_raw()); + margins.with(|v| style.margins.set_all(Some(v))); + left.with(|v| style.margins.left = Some(v)); + right.with(|v| style.margins.right = Some(v)); + top.with(|v| style.margins.top = Some(v)); + bottom.with(|v| style.margins.bottom = Some(v)); - Pass::okay(vec![SetPageStyle(style)]) + if flip { + style.size.swap(); } + + Pass::commands(vec![SetPageStyle(style)], f) } /// `pagebreak`: Ends the current page. -pub fn pagebreak(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { +pub async fn pagebreak(args: TableValue, _: LayoutContext<'_>) -> Pass<Value> { let mut f = Feedback::new(); - call.args.unexpected(&mut f); - Pass::node(PageBreakNode, f) -} - -#[derive(Debug, Default, Clone, PartialEq)] -struct PageBreakNode; - -#[async_trait(?Send)] -impl Layout for PageBreakNode { - async fn layout<'a>(&'a self, _: LayoutContext<'_>) -> Pass<Commands<'a>> { - Pass::okay(vec![BreakPage]) - } + args.unexpected(&mut f); + Pass::commands(vec![BreakPage], f) } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 81112cbd..3cd775c9 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -6,44 +6,32 @@ use super::*; /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub fn h(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { - spacing(call, Horizontal) +pub async fn h(args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> { + spacing(args, ctx, Horizontal).await } /// `v`: Add vertical spacing. /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub fn v(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { - spacing(call, Vertical) +pub async fn v(args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> { + spacing(args, ctx, Vertical).await } -fn spacing(call: FuncCall, axis: SpecAxis) -> Pass<SyntaxNode> { +async fn spacing( + mut args: TableValue, + ctx: LayoutContext<'_>, + axis: SpecAxis, +) -> Pass<Value> { let mut f = Feedback::new(); - let mut args = call.args; - let node = SpacingNode { - spacing: args.expect::<ScaleLength>(&mut f) - .map(|s| (axis, s)) - .or_missing(call.name.span, "spacing", &mut f), - }; + let spacing = args.expect::<ScaleLength>(&mut f).map(|s| (axis, s)); args.unexpected(&mut f); - Pass::node(node, f) -} - -#[derive(Debug, Clone, PartialEq)] -struct SpacingNode { - spacing: Option<(SpecAxis, ScaleLength)>, -} -#[async_trait(?Send)] -impl Layout for SpacingNode { - async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass<Commands<'a>> { - Pass::okay(if let Some((axis, spacing)) = self.spacing { - let axis = axis.to_generic(ctx.axes); - let spacing = spacing.raw_scaled(ctx.style.text.font_size()); - vec![AddSpacing(spacing, SpacingKind::Hard, axis)] - } else { - vec![] - }) - } + Pass::commands(if let Some((axis, spacing)) = spacing { + let axis = axis.to_generic(ctx.axes); + let spacing = spacing.raw_scaled(ctx.style.text.font_size()); + vec![AddSpacing(spacing, SpacingKind::Hard, axis)] + } else { + vec![] + }, f) } diff --git a/src/library/val.rs b/src/library/val.rs deleted file mode 100644 index 9df55401..00000000 --- a/src/library/val.rs +++ /dev/null @@ -1,28 +0,0 @@ -use super::*; - -/// `val`: Ignores all arguments and layouts its body flatly. -/// -/// This is also the fallback function, which is used when a function name -/// cannot be resolved. -pub fn val(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> { - let mut args = call.args; - let node = ValNode { - content: args.take::<SyntaxTree>(), - }; - Pass::node(node, Feedback::new()) -} - -#[derive(Debug, Clone, PartialEq)] -struct ValNode { - content: Option<SyntaxTree>, -} - -#[async_trait(?Send)] -impl Layout for ValNode { - async fn layout<'a>(&'a self, _: LayoutContext<'_>) -> Pass<Commands<'a>> { - Pass::okay(match &self.content { - Some(tree) => vec![LayoutSyntaxTree(tree)], - None => vec![], - }) - } -} |
