summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-04 22:36:20 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-04 22:36:20 +0200
commit605ab104c5e041c345007020d277b4c6267debe6 (patch)
treec18f3333a0c0e0527ad1039a498cb210300f7fd9 /src/library
parentef8aa763faa59fd62c90c6d6245e8d2c5eece35e (diff)
Better argument parsing 🥙
Diffstat (limited to 'src/library')
-rw-r--r--src/library/align.rs44
-rw-r--r--src/library/boxed.rs15
-rw-r--r--src/library/color.rs16
-rw-r--r--src/library/font.rs37
-rw-r--r--src/library/page.rs26
-rw-r--r--src/library/spacing.rs13
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![]