diff --git a/src/eval/value.rs b/src/eval/value.rs index dda1c3e1e..e8ecffa2e 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -55,11 +55,11 @@ pub enum Value { impl Value { /// Create a new template value consisting of a single dynamic node. - pub fn template(name: impl Into, f: F) -> Self + pub fn template(f: F) -> Self where F: Fn(&mut ExecContext) + 'static, { - Self::Template(vec![TemplateNode::Func(TemplateFunc::new(name, f))]) + Self::Template(vec![TemplateNode::Func(TemplateFunc::new(f))]) } /// The name of the stored value's type. @@ -193,23 +193,15 @@ pub type ExprMap = HashMap<*const Expr, Value>; /// A reference-counted dynamic template node that can implement custom /// behaviour. #[derive(Clone)] -pub struct TemplateFunc { - name: String, - f: Rc, -} +pub struct TemplateFunc(Rc); impl TemplateFunc { /// Create a new function template from a rust function or closure. - pub fn new(name: impl Into, f: F) -> Self + pub fn new(f: F) -> Self where F: Fn(&mut ExecContext) + 'static, { - Self { name: name.into(), f: Rc::new(f) } - } - - /// The name of the template node. - pub fn name(&self) -> &str { - &self.name + Self(Rc::new(f)) } } @@ -224,7 +216,7 @@ impl Deref for TemplateFunc { type Target = dyn Fn(&mut ExecContext); fn deref(&self) -> &Self::Target { - self.f.as_ref() + self.0.as_ref() } } diff --git a/src/library/elements.rs b/src/library/elements.rs index b1b5c1f9e..5271788fa 100644 --- a/src/library/elements.rs +++ b/src/library/elements.rs @@ -25,7 +25,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { } } - Value::template("image", move |ctx| { + Value::template(move |ctx| { if let Some(node) = node { ctx.push_into_par(node); } @@ -37,8 +37,8 @@ pub fn rect(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let width = args.named(ctx, "width"); let height = args.named(ctx, "height"); let fill = args.named(ctx, "fill"); - let body = args.eat::(ctx).unwrap_or_default(); - rect_impl("rect", width, height, None, fill, body) + let body = args.eat(ctx).unwrap_or_default(); + rect_impl(width, height, None, fill, body) } /// `square`: A square with optional content. @@ -47,19 +47,18 @@ pub fn square(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let width = length.or_else(|| args.named(ctx, "width")); let height = width.is_none().then(|| args.named(ctx, "height")).flatten(); let fill = args.named(ctx, "fill"); - let body = args.eat::(ctx).unwrap_or_default(); - rect_impl("square", width, height, Some(N64::from(1.0)), fill, body) + let body = args.eat(ctx).unwrap_or_default(); + rect_impl(width, height, Some(N64::from(1.0)), fill, body) } fn rect_impl( - name: &str, width: Option, height: Option, aspect: Option, fill: Option, body: TemplateValue, ) -> Value { - Value::template(name, move |ctx| { + Value::template(move |ctx| { let mut stack = ctx.exec_template_stack(&body); stack.aspect = aspect; @@ -82,8 +81,8 @@ pub fn ellipse(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let width = args.named(ctx, "width"); let height = args.named(ctx, "height"); let fill = args.named(ctx, "fill"); - let body = args.eat::(ctx).unwrap_or_default(); - ellipse_impl("ellipse", width, height, None, fill, body) + let body = args.eat(ctx).unwrap_or_default(); + ellipse_impl(width, height, None, fill, body) } /// `circle`: A circle with optional content. @@ -92,19 +91,18 @@ pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let width = radius.or_else(|| args.named(ctx, "width")); let height = width.is_none().then(|| args.named(ctx, "height")).flatten(); let fill = args.named(ctx, "fill"); - let body = args.eat::(ctx).unwrap_or_default(); - ellipse_impl("circle", width, height, Some(N64::from(1.0)), fill, body) + let body = args.eat(ctx).unwrap_or_default(); + ellipse_impl(width, height, Some(N64::from(1.0)), fill, body) } fn ellipse_impl( - name: &str, width: Option, height: Option, aspect: Option, fill: Option, body: TemplateValue, ) -> Value { - Value::template(name, move |ctx| { + Value::template(move |ctx| { // This padding ratio ensures that the rectangular padded region fits // perfectly into the ellipse. const PAD: f64 = 0.5 - SQRT_2 / 4.0; diff --git a/src/library/layout.rs b/src/library/layout.rs index cba77c726..10389779e 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -1,9 +1,10 @@ use super::*; -use crate::layout::{GridNode, PadNode, StackChild, StackNode, TrackSizing}; +use crate::layout::{FixedNode, GridNode, PadNode, StackChild, StackNode, TrackSizing}; use crate::paper::{Paper, PaperClass}; /// `page`: Configure pages. pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { + let span = args.span; let paper = args.eat::>(ctx).and_then(|name| { Paper::from_name(&name.v).or_else(|| { ctx.diag(error!(name.span, "invalid paper name")); @@ -20,9 +21,8 @@ pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let bottom = args.named(ctx, "bottom"); let flip = args.named(ctx, "flip"); let body = args.eat::(ctx); - let span = args.span; - Value::template("page", move |ctx| { + Value::template(move |ctx| { let snapshot = ctx.state.clone(); if let Some(paper) = paper { @@ -79,29 +79,24 @@ pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `pagebreak`: Start a new page. pub fn pagebreak(_: &mut EvalContext, args: &mut FuncArgs) -> Value { let span = args.span; - Value::template("pagebreak", move |ctx| { + Value::template(move |ctx| { ctx.pagebreak(true, true, span); }) } /// `h`: Horizontal spacing. pub fn h(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - spacing_impl("h", ctx, args, GenAxis::Cross) + spacing_impl(ctx, args, GenAxis::Cross) } /// `v`: Vertical spacing. pub fn v(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - spacing_impl("v", ctx, args, GenAxis::Main) + spacing_impl(ctx, args, GenAxis::Main) } -fn spacing_impl( - name: &str, - ctx: &mut EvalContext, - args: &mut FuncArgs, - axis: GenAxis, -) -> Value { +fn spacing_impl(ctx: &mut EvalContext, args: &mut FuncArgs, axis: GenAxis) -> Value { let spacing: Option = args.expect(ctx, "spacing"); - Value::template(name, move |ctx| { + Value::template(move |ctx| { if let Some(linear) = spacing { // TODO: Should this really always be font-size relative? let amount = linear.resolve(ctx.state.font.size); @@ -130,7 +125,7 @@ pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { } } - Value::template("align", move |ctx| { + Value::template(move |ctx| { let snapshot = ctx.state.clone(); if let Some(horizontal) = horizontal { @@ -222,7 +217,7 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let top = args.named(ctx, "top"); let right = args.named(ctx, "right"); let bottom = args.named(ctx, "bottom"); - let body = args.expect::(ctx, "body").unwrap_or_default(); + let body = args.expect(ctx, "body").unwrap_or_default(); let padding = Sides::new( left.or(all).unwrap_or_default(), @@ -231,7 +226,7 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { bottom.or(all).unwrap_or_default(), ); - Value::template("pad", move |ctx| { + Value::template(move |ctx| { let child = ctx.exec_template_stack(&body).into(); ctx.push_into_stack(PadNode { padding, child }); }) @@ -240,9 +235,9 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `stack`: Stack children along an axis. pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let dir = args.named::(ctx, "dir").unwrap_or(Dir::TTB); - let children = args.all::(ctx); + let children = args.all(ctx); - Value::template("stack", move |ctx| { + Value::template(move |ctx| { let children = children .iter() .map(|child| { @@ -271,9 +266,9 @@ pub fn grid(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let gutter_rows = args.named::(ctx, "gutter-rows"); let column_dir = args.named(ctx, "column-dir"); let row_dir = args.named(ctx, "row-dir"); - let children = args.all::(ctx); + let children = args.all(ctx); - Value::template("grid", move |ctx| { + Value::template(move |ctx| { let children = children .iter() .map(|child| ctx.exec_template_stack(child).into()) diff --git a/src/library/text.rs b/src/library/text.rs index f80b417c2..6a2fe9bbc 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -19,7 +19,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let monospace = args.named(ctx, "monospace"); let body = args.eat::(ctx); - Value::template("font", move |ctx| { + Value::template(move |ctx| { let snapshot = ctx.state.clone(); let font = ctx.state.font_mut(); @@ -162,7 +162,7 @@ pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let leading = args.named(ctx, "leading"); let word_spacing = args.named(ctx, "word-spacing"); - Value::template("par", move |ctx| { + Value::template(move |ctx| { if let Some(spacing) = spacing { ctx.state.par.spacing = spacing; } @@ -191,7 +191,7 @@ pub fn lang(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { None => None, }; - Value::template("lang", move |ctx| { + Value::template(move |ctx| { if let Some(dir) = dir.or(iso) { ctx.state.lang.dir = dir; } @@ -210,21 +210,20 @@ fn lang_dir(iso: &str) -> Dir { /// `strike`: Enable striken-through text. pub fn strike(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - line_impl("strike", ctx, args, |font| &mut font.strikethrough) + line_impl(ctx, args, |font| &mut font.strikethrough) } /// `underline`: Enable underlined text. pub fn underline(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - line_impl("underline", ctx, args, |font| &mut font.underline) + line_impl(ctx, args, |font| &mut font.underline) } /// `overline`: Add an overline above text. pub fn overline(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - line_impl("overline", ctx, args, |font| &mut font.overline) + line_impl(ctx, args, |font| &mut font.overline) } fn line_impl( - name: &str, ctx: &mut EvalContext, args: &mut FuncArgs, substate: fn(&mut FontState) -> &mut Option>, @@ -245,7 +244,7 @@ fn line_impl( }) }); - Value::template(name, move |ctx| { + Value::template(move |ctx| { let snapshot = ctx.state.clone(); *substate(ctx.state.font_mut()) = state.clone();