diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-04 22:36:20 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-04 22:36:20 +0200 |
| commit | 605ab104c5e041c345007020d277b4c6267debe6 (patch) | |
| tree | c18f3333a0c0e0527ad1039a498cb210300f7fd9 /src/library | |
| parent | ef8aa763faa59fd62c90c6d6245e8d2c5eece35e (diff) | |
Better argument parsing 🥙
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/align.rs | 44 | ||||
| -rw-r--r-- | src/library/boxed.rs | 15 | ||||
| -rw-r--r-- | src/library/color.rs | 16 | ||||
| -rw-r--r-- | src/library/font.rs | 37 | ||||
| -rw-r--r-- | src/library/page.rs | 26 | ||||
| -rw-r--r-- | src/library/spacing.rs | 13 |
6 files changed, 80 insertions, 71 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index 0c145e5f..674ecceb 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -14,21 +14,41 @@ use super::*; /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub async fn align(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { - let content = args.take::<SynTree>(); - let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut ctx.f); - let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut ctx.f); - let all = args - .take_all_num_vals::<Spanned<SpecAlign>>() +pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value { + let body = args.find::<SynTree>(); + + let h = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal"); + let v = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical"); + let pos = args.find_all::<Spanned<SpecAlign>>(); + + let iter = pos .map(|align| (align.v.axis(), align)) .chain(h.into_iter().map(|align| (Some(SpecAxis::Horizontal), align))) .chain(v.into_iter().map(|align| (Some(SpecAxis::Vertical), align))); + let aligns = parse_aligns(ctx, iter); + + args.done(ctx); + Value::Commands(match body { + Some(tree) => vec![ + SetAlignment(aligns), + LayoutSyntaxTree(tree), + SetAlignment(ctx.state.align), + ], + None => vec![SetAlignment(aligns)], + }) +} + +/// Deduplicate alignments and deduce to which axes they apply. +fn parse_aligns( + ctx: &mut LayoutContext, + iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<SpecAlign>)>, +) -> LayoutAlign { let mut aligns = ctx.state.align; let mut had = [false; 2]; let mut deferred_center = false; - for (axis, align) in all { + for (axis, align) in iter { // Check whether we know which axis this alignment belongs to. We don't // if the alignment is `center` for a positional argument. Then we set // `deferred_center` to true and handle the situation once we know more. @@ -80,13 +100,5 @@ pub async fn align(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { aligns.primary = GenAlign::Center; } - args.unexpected(&mut ctx.f); - Value::Commands(match content { - Some(tree) => vec![ - SetAlignment(aligns), - LayoutSyntaxTree(tree), - SetAlignment(ctx.state.align), - ], - None => vec![SetAlignment(aligns)], - }) + aligns } diff --git a/src/library/boxed.rs b/src/library/boxed.rs index c97df8d0..81e3a96a 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -6,31 +6,32 @@ use crate::geom::Linear; /// # Keyword arguments /// - `width`: The width of the box (length or relative to parent's width). /// - `height`: The height of the box (length or relative to parent's height). -pub async fn boxed(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { - let content = args.take::<SynTree>().unwrap_or_default(); +pub async fn boxed(mut args: Args, ctx: &mut LayoutContext) -> Value { + let body = args.find::<SynTree>().unwrap_or_default(); + let width = args.get::<_, Linear>(ctx, "width"); + let height = args.get::<_, Linear>(ctx, "height"); + args.done(ctx); let constraints = &mut ctx.constraints; constraints.base = constraints.spaces[0].size; constraints.spaces.truncate(1); constraints.repeat = false; - if let Some(width) = args.take_key::<Linear>("width", &mut ctx.f) { + if let Some(width) = width { let abs = width.eval(constraints.base.width); constraints.base.width = abs; constraints.spaces[0].size.width = abs; constraints.spaces[0].expansion.horizontal = true; } - if let Some(height) = args.take_key::<Linear>("height", &mut ctx.f) { + if let Some(height) = height { let abs = height.eval(constraints.base.height); constraints.base.height = abs; constraints.spaces[0].size.height = abs; constraints.spaces[0].expansion.vertical = true; } - args.unexpected(&mut ctx.f); - - let layouted = layout_tree(&content, ctx).await; + let layouted = layout_tree(&body, ctx).await; let layout = layouted.into_iter().next().unwrap(); Value::Commands(vec![Add(layout)]) diff --git a/src/library/color.rs b/src/library/color.rs index 22029b1f..143ce70a 100644 --- a/src/library/color.rs +++ b/src/library/color.rs @@ -2,24 +2,22 @@ use super::*; use crate::color::RgbaColor; /// `rgb`: Create an RGB(A) color. -pub async fn rgb(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { - let mut f = Feedback::new(); - - let r = args.expect::<Spanned<i64>>("red value", Span::ZERO, &mut f); - let g = args.expect::<Spanned<i64>>("green value", Span::ZERO, &mut f); - let b = args.expect::<Spanned<i64>>("blue value", Span::ZERO, &mut f); - let a = args.take::<Spanned<i64>>(); +pub async fn rgb(mut args: Args, ctx: &mut LayoutContext) -> Value { + let r = args.get::<_, Spanned<i64>>(ctx, 0); + let g = args.get::<_, Spanned<i64>>(ctx, 1); + let b = args.get::<_, Spanned<i64>>(ctx, 2); + let a = args.get::<_, Spanned<i64>>(ctx, 3); + args.done(ctx); let mut clamp = |component: Option<Spanned<i64>>, default| { component.map_or(default, |c| { if c.v < 0 || c.v > 255 { - error!(@f, c.span, "should be between 0 and 255") + error!(@ctx.f, c.span, "should be between 0 and 255") } c.v.max(0).min(255) as u8 }) }; - args.unexpected(&mut ctx.f); Value::Color(RgbaColor::new( clamp(r, 0), clamp(g, 0), diff --git a/src/library/font.rs b/src/library/font.rs index cfda3beb..0a28beaa 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -49,13 +49,13 @@ use crate::geom::Linear; /// ```typst /// [font: "My Serif", serif] /// ``` -pub async fn font(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { +pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value { let mut text = ctx.state.text.clone(); - let mut updated_fallback = false; + let mut needs_flatten = false; - let content = args.take::<SynTree>(); + let body = args.find::<SynTree>(); - if let Some(linear) = args.take::<Linear>() { + if let Some(linear) = args.find::<Linear>() { if linear.rel == 0.0 { text.font_size.base = linear.abs; text.font_size.scale = Linear::rel(1.0); @@ -64,44 +64,41 @@ pub async fn font(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { } } - let list: Vec<_> = args - .take_all_num_vals::<StringLike>() - .map(|s| s.to_lowercase()) - .collect(); - + let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect(); if !list.is_empty() { text.fallback.list = list; - updated_fallback = true; + needs_flatten = true; } - if let Some(style) = args.take_key::<FontStyle>("style", &mut ctx.f) { + if let Some(style) = args.get::<_, FontStyle>(ctx, "style") { text.variant.style = style; } - if let Some(weight) = args.take_key::<FontWeight>("weight", &mut ctx.f) { + if let Some(weight) = args.get::<_, FontWeight>(ctx, "weight") { text.variant.weight = weight; } - if let Some(stretch) = args.take_key::<FontStretch>("stretch", &mut ctx.f) { + if let Some(stretch) = args.get::<_, FontStretch>(ctx, "stretch") { text.variant.stretch = stretch; } - for (class, mut dict) in args.take_all_str::<ValueDict>() { - let fallback = dict - .take_all_num_vals::<StringLike>() + for (class, dict) in args.find_all_str::<Spanned<ValueDict>>() { + let fallback = Args(dict) + .find_all::<StringLike>() .map(|s| s.to_lowercase()) .collect(); text.fallback.update_class_list(class, fallback); - updated_fallback = true; + needs_flatten = true; } - if updated_fallback { + args.done(ctx); + + if needs_flatten { text.fallback.flatten(); } - args.unexpected(&mut ctx.f); - Value::Commands(match content { + Value::Commands(match body { Some(tree) => vec![ SetTextState(text), LayoutSyntaxTree(tree), diff --git a/src/library/page.rs b/src/library/page.rs index b557650b..db76d2a1 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -19,54 +19,54 @@ use crate::paper::{Paper, PaperClass}; /// - `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 async fn page(mut args: ValueDict, ctx: &mut LayoutContext) -> Value { +pub async fn page(mut args: Args, ctx: &mut LayoutContext) -> Value { let mut page = ctx.state.page.clone(); - if let Some(paper) = args.take::<Paper>() { + if let Some(paper) = args.find::<Paper>() { page.class = paper.class; page.size = paper.size(); } - if let Some(Absolute(width)) = args.take_key::<Absolute>("width", &mut ctx.f) { + if let Some(Absolute(width)) = args.get::<_, Absolute>(ctx, "width") { page.class = PaperClass::Custom; page.size.width = width; } - if let Some(Absolute(height)) = args.take_key::<Absolute>("height", &mut ctx.f) { + if let Some(Absolute(height)) = args.get::<_, Absolute>(ctx, "height") { page.class = PaperClass::Custom; page.size.height = height; } - if let Some(margins) = args.take_key::<Linear>("margins", &mut ctx.f) { + if let Some(margins) = args.get::<_, Linear>(ctx, "margins") { page.margins = Sides::uniform(Some(margins)); } - if let Some(left) = args.take_key::<Linear>("left", &mut ctx.f) { + if let Some(left) = args.get::<_, Linear>(ctx, "left") { page.margins.left = Some(left); } - if let Some(top) = args.take_key::<Linear>("top", &mut ctx.f) { + if let Some(top) = args.get::<_, Linear>(ctx, "top") { page.margins.top = Some(top); } - if let Some(right) = args.take_key::<Linear>("right", &mut ctx.f) { + if let Some(right) = args.get::<_, Linear>(ctx, "right") { page.margins.right = Some(right); } - if let Some(bottom) = args.take_key::<Linear>("bottom", &mut ctx.f) { + if let Some(bottom) = args.get::<_, Linear>(ctx, "bottom") { page.margins.bottom = Some(bottom); } - if args.take_key::<bool>("flip", &mut ctx.f).unwrap_or(false) { + if args.get::<_, bool>(ctx, "flip").unwrap_or(false) { mem::swap(&mut page.size.width, &mut page.size.height); } - args.unexpected(&mut ctx.f); + args.done(ctx); Value::Commands(vec![SetPageState(page)]) } /// `pagebreak`: Ends the current page. -pub async fn pagebreak(args: ValueDict, ctx: &mut LayoutContext) -> Value { - args.unexpected(&mut ctx.f); +pub async fn pagebreak(args: Args, ctx: &mut LayoutContext) -> Value { + args.done(ctx); Value::Commands(vec![BreakPage]) } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 9ca68263..b97f4640 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -6,7 +6,7 @@ use crate::layout::SpacingKind; /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn h(args: ValueDict, ctx: &mut LayoutContext) -> Value { +pub async fn h(args: Args, ctx: &mut LayoutContext) -> Value { spacing(args, ctx, SpecAxis::Horizontal) } @@ -14,16 +14,17 @@ pub async fn h(args: ValueDict, ctx: &mut LayoutContext) -> Value { /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn v(args: ValueDict, ctx: &mut LayoutContext) -> Value { +pub async fn v(args: Args, ctx: &mut LayoutContext) -> Value { spacing(args, ctx, SpecAxis::Vertical) } -fn spacing(mut args: ValueDict, ctx: &mut LayoutContext, axis: SpecAxis) -> Value { - let spacing = args.expect::<Linear>("spacing", Span::ZERO, &mut ctx.f); - args.unexpected(&mut ctx.f); +fn spacing(mut args: Args, ctx: &mut LayoutContext, axis: SpecAxis) -> Value { + let spacing = args.get::<_, Linear>(ctx, 0); + args.done(ctx); + Value::Commands(if let Some(spacing) = spacing { - let axis = axis.to_gen(ctx.state.sys); let spacing = spacing.eval(ctx.state.text.font_size()); + let axis = axis.to_gen(ctx.state.sys); vec![AddSpacing(spacing, SpacingKind::Hard, axis)] } else { vec![] |
