diff options
Diffstat (limited to 'library')
42 files changed, 697 insertions, 820 deletions
diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs index d4a4bcf6..25df817d 100644 --- a/library/src/compute/calc.rs +++ b/library/src/compute/calc.rs @@ -10,28 +10,28 @@ use crate::prelude::*; /// A module with computational functions. pub fn module() -> Module { let mut scope = Scope::new(); - scope.def_func::<AbsFunc>("abs"); - scope.def_func::<PowFunc>("pow"); - scope.def_func::<SqrtFunc>("sqrt"); - scope.def_func::<SinFunc>("sin"); - scope.def_func::<CosFunc>("cos"); - scope.def_func::<TanFunc>("tan"); - scope.def_func::<AsinFunc>("asin"); - scope.def_func::<AcosFunc>("acos"); - scope.def_func::<AtanFunc>("atan"); - scope.def_func::<SinhFunc>("sinh"); - scope.def_func::<CoshFunc>("cosh"); - scope.def_func::<TanhFunc>("tanh"); - scope.def_func::<LogFunc>("log"); - scope.def_func::<FloorFunc>("floor"); - scope.def_func::<CeilFunc>("ceil"); - scope.def_func::<RoundFunc>("round"); - scope.def_func::<ClampFunc>("clamp"); - scope.def_func::<MinFunc>("min"); - scope.def_func::<MaxFunc>("max"); - scope.def_func::<EvenFunc>("even"); - scope.def_func::<OddFunc>("odd"); - scope.def_func::<ModFunc>("mod"); + scope.define("abs", abs); + scope.define("pow", pow); + scope.define("sqrt", sqrt); + scope.define("sin", sin); + scope.define("cos", cos); + scope.define("tan", tan); + scope.define("asin", asin); + scope.define("acos", acos); + scope.define("atan", atan); + scope.define("sinh", sinh); + scope.define("cosh", cosh); + scope.define("tanh", tanh); + scope.define("log", log); + scope.define("floor", floor); + scope.define("ceil", ceil); + scope.define("round", round); + scope.define("clamp", clamp); + scope.define("min", min); + scope.define("max", max); + scope.define("even", even); + scope.define("odd", odd); + scope.define("mod", mod_); scope.define("inf", Value::Float(f64::INFINITY)); scope.define("nan", Value::Float(f64::NAN)); scope.define("pi", Value::Float(std::f64::consts::PI)); @@ -48,15 +48,15 @@ pub fn module() -> Module { /// #calc.abs(2fr) /// ``` /// -/// ## Parameters -/// - value: `ToAbs` (positional, required) -/// The value whose absolute value to calculate. -/// /// Display: Absolute /// Category: calculate +/// Returns: any #[func] -pub fn abs(args: &mut Args) -> SourceResult<Value> { - Ok(args.expect::<ToAbs>("value")?.0) +pub fn abs( + /// The value whose absolute value to calculate. + value: ToAbs, +) -> Value { + value.0 } /// A value of which the absolute value can be taken. @@ -80,27 +80,27 @@ cast_from_value! { /// #calc.pow(2, 3) /// ``` /// -/// ## Parameters -/// - base: `Num` (positional, required) -/// The base of the power. -/// - exponent: `Num` (positional, required) -/// The exponent of the power. Must be non-negative. -/// /// Display: Power /// Category: calculate +/// Returns: integer or float #[func] -pub fn pow(args: &mut Args) -> SourceResult<Value> { - let base = args.expect::<Num>("base")?; - let exponent = args - .expect::<Spanned<Num>>("exponent") - .and_then(|n| match n.v { - Num::Int(i) if i > u32::MAX as i64 => bail!(n.span, "exponent too large"), - Num::Int(i) if i >= 0 => Ok(n), - Num::Float(f) if f >= 0.0 => Ok(n), - _ => bail!(n.span, "exponent must be non-negative"), - })? - .v; - Ok(base.apply2(exponent, |a, b| a.pow(b as u32), f64::powf)) +pub fn pow( + /// The base of the power. + base: Num, + /// The exponent of the power. Must be non-negative. + exponent: Spanned<Num>, +) -> Value { + let exponent = match exponent.v { + Num::Int(i) if i > u32::MAX as i64 => { + bail!(exponent.span, "exponent too large"); + } + Num::Int(0..) => exponent.v, + Num::Float(f) if f >= 0.0 => exponent.v, + _ => { + bail!(exponent.span, "exponent must be non-negative"); + } + }; + base.apply2(exponent, |a, b| a.pow(b as u32), f64::powf) } /// Calculate the square root of a number. @@ -111,19 +111,18 @@ pub fn pow(args: &mut Args) -> SourceResult<Value> { /// #calc.sqrt(2.5) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number whose square root to calculate. Must be non-negative. -/// /// Display: Square Root /// Category: calculate +/// Returns: float #[func] -pub fn sqrt(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Spanned<Num>>("value")?; +pub fn sqrt( + /// The number whose square root to calculate. Must be non-negative. + value: Spanned<Num>, +) -> Value { if value.v.float() < 0.0 { bail!(value.span, "cannot take square root of negative number"); } - Ok(Value::Float(value.v.float().sqrt())) + Value::Float(value.v.float().sqrt()) } /// Calculate the sine of an angle. @@ -138,20 +137,19 @@ pub fn sqrt(args: &mut Args) -> SourceResult<Value> { /// #calc.sin(90deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose sine to calculate. -/// /// Display: Sine /// Category: calculate +/// Returns: float #[func] -pub fn sin(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn sin( + /// The angle whose sine to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.sin(), AngleLike::Int(n) => (n as f64).sin(), AngleLike::Float(n) => n.sin(), - })) + }) } /// Calculate the cosine of an angle. @@ -161,25 +159,24 @@ pub fn sin(args: &mut Args) -> SourceResult<Value> { /// /// ## Example /// ```example -/// #calc.cos(90deg) +/// #calc.cos(90deg) \ /// #calc.cos(1.5) \ /// #calc.cos(90deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose cosine to calculate. -/// /// Display: Cosine /// Category: calculate +/// Returns: float #[func] -pub fn cos(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn cos( + /// The angle whose cosine to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.cos(), AngleLike::Int(n) => (n as f64).cos(), AngleLike::Float(n) => n.cos(), - })) + }) } /// Calculate the tangent of an angle. @@ -193,20 +190,19 @@ pub fn cos(args: &mut Args) -> SourceResult<Value> { /// #calc.tan(90deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose tangent to calculate. -/// /// Display: Tangent /// Category: calculate +/// Returns: float #[func] -pub fn tan(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn tan( + /// The angle whose tangent to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.tan(), AngleLike::Int(n) => (n as f64).tan(), AngleLike::Float(n) => n.tan(), - })) + }) } /// Calculate the arcsine of a number. @@ -217,20 +213,19 @@ pub fn tan(args: &mut Args) -> SourceResult<Value> { /// #calc.asin(1) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number whose arcsine to calculate. Must be between -1 and 1. -/// /// Display: Arcsine /// Category: calculate +/// Returns: angle #[func] -pub fn asin(args: &mut Args) -> SourceResult<Value> { - let Spanned { v, span } = args.expect::<Spanned<Num>>("value")?; - let val = v.float(); +pub fn asin( + /// The number whose arcsine to calculate. Must be between -1 and 1. + value: Spanned<Num>, +) -> Value { + let val = value.v.float(); if val < -1.0 || val > 1.0 { - bail!(span, "arcsin must be between -1 and 1"); + bail!(value.span, "arcsin must be between -1 and 1"); } - Ok(Value::Angle(Angle::rad(val.asin()))) + Value::Angle(Angle::rad(val.asin())) } /// Calculate the arccosine of a number. @@ -241,20 +236,19 @@ pub fn asin(args: &mut Args) -> SourceResult<Value> { /// #calc.acos(1) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number whose arccosine to calculate. Must be between -1 and 1. -/// /// Display: Arccosine /// Category: calculate +/// Returns: angle #[func] -pub fn acos(args: &mut Args) -> SourceResult<Value> { - let Spanned { v, span } = args.expect::<Spanned<Num>>("value")?; - let val = v.float(); +pub fn acos( + /// The number whose arcsine to calculate. Must be between -1 and 1. + value: Spanned<Num>, +) -> Value { + let val = value.v.float(); if val < -1.0 || val > 1.0 { - bail!(span, "arccos must be between -1 and 1"); + bail!(value.span, "arccos must be between -1 and 1"); } - Ok(Value::Angle(Angle::rad(val.acos()))) + Value::Angle(Angle::rad(val.acos())) } /// Calculate the arctangent of a number. @@ -265,16 +259,15 @@ pub fn acos(args: &mut Args) -> SourceResult<Value> { /// #calc.atan(1) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number whose arctangent to calculate. -/// /// Display: Arctangent /// Category: calculate +/// Returns: angle #[func] -pub fn atan(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Num>("value")?; - Ok(Value::Angle(Angle::rad(value.float().atan()))) +pub fn atan( + /// The number whose arctangent to calculate. + value: Num, +) -> Value { + Value::Angle(Angle::rad(value.float().atan())) } /// Calculate the hyperbolic sine of an angle. @@ -287,20 +280,19 @@ pub fn atan(args: &mut Args) -> SourceResult<Value> { /// #calc.sinh(45deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose hyperbolic sine to calculate. -/// /// Display: Hyperbolic sine /// Category: calculate +/// Returns: float #[func] -pub fn sinh(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn sinh( + /// The angle whose hyperbolic sine to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.to_rad().sinh(), AngleLike::Int(n) => (n as f64).sinh(), AngleLike::Float(n) => n.sinh(), - })) + }) } /// Calculate the hyperbolic cosine of an angle. @@ -313,20 +305,19 @@ pub fn sinh(args: &mut Args) -> SourceResult<Value> { /// #calc.cosh(45deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose hyperbolic cosine to calculate. -/// /// Display: Hyperbolic cosine /// Category: calculate +/// Returns: float #[func] -pub fn cosh(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn cosh( + /// The angle whose hyperbolic cosine to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.to_rad().cosh(), AngleLike::Int(n) => (n as f64).cosh(), AngleLike::Float(n) => n.cosh(), - })) + }) } /// Calculate the hyperbolic tangent of an angle. @@ -339,20 +330,19 @@ pub fn cosh(args: &mut Args) -> SourceResult<Value> { /// #calc.tanh(45deg) /// ``` /// -/// ## Parameters -/// - angle: `AngleLike` (positional, required) -/// The angle whose hyperbolic tangent to calculate. -/// /// Display: Hyperbolic tangent /// Category: calculate +/// Returns: float #[func] -pub fn tanh(args: &mut Args) -> SourceResult<Value> { - let arg = args.expect::<AngleLike>("angle")?; - Ok(Value::Float(match arg { +pub fn tanh( + /// The angle whose hyperbolic tangent to calculate. + angle: AngleLike, +) -> Value { + Value::Float(match angle { AngleLike::Angle(a) => a.to_rad().tanh(), AngleLike::Int(n) => (n as f64).tanh(), AngleLike::Float(n) => n.tanh(), - })) + }) } /// Calculate the logarithm of a number. @@ -361,22 +351,22 @@ pub fn tanh(args: &mut Args) -> SourceResult<Value> { /// /// ## Example /// ```example -/// #calc.log(100) \ +/// #calc.log(100) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number whose logarithm to calculate. -/// - base: `Num` (named) -/// The base of the logarithm. -/// /// Display: Logarithm /// Category: calculate +/// Returns: float #[func] -pub fn log(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<f64>("value")?; - let base = args.named::<f64>("base")?.unwrap_or_else(|| 10.0); - Ok(Value::Float(value.log(base))) +pub fn log( + /// The number whose logarithm to calculate. + value: f64, + /// The base of the logarithm. + #[named] + #[default(10.0)] + base: f64, +) -> Value { + Value::Float(value.log(base)) } /// Round a number down to the nearest integer. @@ -390,19 +380,18 @@ pub fn log(args: &mut Args) -> SourceResult<Value> { /// #calc.floor(500.1) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number to round down. -/// /// Display: Round down /// Category: calculate +/// Returns: integer #[func] -pub fn floor(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Num>("value")?; - Ok(match value { +pub fn floor( + /// The number to round down. + value: Num, +) -> Value { + match value { Num::Int(n) => Value::Int(n), Num::Float(n) => Value::Int(n.floor() as i64), - }) + } } /// Round a number up to the nearest integer. @@ -416,19 +405,18 @@ pub fn floor(args: &mut Args) -> SourceResult<Value> { /// #calc.ceil(500.1) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number to round up. -/// /// Display: Round up /// Category: calculate +/// Returns: integer #[func] -pub fn ceil(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Num>("value")?; - Ok(match value { +pub fn ceil( + /// The number to round up. + value: Num, +) -> Value { + match value { Num::Int(n) => Value::Int(n), Num::Float(n) => Value::Int(n.ceil() as i64), - }) + } } /// Round a number to the nearest integer. @@ -442,25 +430,26 @@ pub fn ceil(args: &mut Args) -> SourceResult<Value> { /// #calc.round(3.1415, digits: 2) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number to round. -/// - digits: `i64` (named) -/// /// Display: Round /// Category: calculate +/// Returns: integer or float #[func] -pub fn round(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Num>("value")?; - let digits = args.named::<u32>("digits")?.unwrap_or(0); - Ok(match value { +pub fn round( + /// The number to round. + value: Num, + /// The number of decimal places. + #[named] + #[default(0)] + digits: i64, +) -> Value { + match value { Num::Int(n) if digits == 0 => Value::Int(n), _ => { let n = value.float(); let factor = 10.0_f64.powi(digits as i32) as f64; Value::Float((n * factor).round() / factor) } - }) + } } /// Clamp a number between a minimum and maximum value. @@ -472,25 +461,22 @@ pub fn round(args: &mut Args) -> SourceResult<Value> { /// #calc.clamp(5, 0, 4) /// ``` /// -/// ## Parameters -/// - value: `Num` (positional, required) -/// The number to clamp. -/// - min: `Num` (positional, required) -/// The inclusive minimum value. -/// - max: `Num` (positional, required) -/// The inclusive maximum value. -/// /// Display: Clamp /// Category: calculate +/// Returns: integer or float #[func] -pub fn clamp(args: &mut Args) -> SourceResult<Value> { - let value = args.expect::<Num>("value")?; - let min = args.expect::<Num>("min")?; - let max = args.expect::<Spanned<Num>>("max")?; +pub fn clamp( + /// The number to clamp. + value: Num, + /// The inclusive minimum value. + min: Num, + /// The inclusive maximum value. + max: Spanned<Num>, +) -> Value { if max.v.float() < min.float() { bail!(max.span, "max must be greater than or equal to min") } - Ok(value.apply3(min, max.v, i64::clamp, f64::clamp)) + value.apply3(min, max.v, i64::clamp, f64::clamp) } /// Determine the minimum of a sequence of values. @@ -501,18 +487,17 @@ pub fn clamp(args: &mut Args) -> SourceResult<Value> { /// #calc.min("typst", "in", "beta") /// ``` /// -/// ## Parameters -/// - values: `Value` (positional, variadic) -/// The sequence of values from which to extract the minimum. -/// Must not be empty. -/// -/// - returns: any -/// /// Display: Minimum /// Category: calculate +/// Returns: any #[func] -pub fn min(args: &mut Args) -> SourceResult<Value> { - minmax(args, Ordering::Less) +pub fn min( + /// The sequence of values from which to extract the minimum. + /// Must not be empty. + #[variadic] + values: Vec<Spanned<Value>>, +) -> Value { + minmax(args.span, values, Ordering::Less)? } /// Determine the maximum of a sequence of values. @@ -523,24 +508,31 @@ pub fn min(args: &mut Args) -> SourceResult<Value> { /// #calc.max("typst", "in", "beta") /// ``` /// -/// ## Parameters -/// - values: `Value` (positional, variadic) -/// The sequence of values from which to extract the maximum. -/// Must not be empty. -/// -/// - returns: any -/// /// Display: Maximum /// Category: calculate +/// Returns: any #[func] -pub fn max(args: &mut Args) -> SourceResult<Value> { - minmax(args, Ordering::Greater) +pub fn max( + /// The sequence of values from which to extract the maximum. + /// Must not be empty. + #[variadic] + values: Vec<Spanned<Value>>, +) -> Value { + minmax(args.span, values, Ordering::Greater)? } /// Find the minimum or maximum of a sequence of values. -fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { - let mut extremum = args.expect::<Value>("value")?; - for Spanned { v, span } in args.all::<Spanned<Value>>()? { +fn minmax( + span: Span, + values: Vec<Spanned<Value>>, + goal: Ordering, +) -> SourceResult<Value> { + let mut iter = values.into_iter(); + let Some(Spanned { v: mut extremum, ..}) = iter.next() else { + bail!(span, "expected at least one value"); + }; + + for Spanned { v, span } in iter { match v.partial_cmp(&extremum) { Some(ordering) => { if ordering == goal { @@ -555,6 +547,7 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { ), } } + Ok(extremum) } @@ -567,17 +560,15 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { /// #range(10).filter(calc.even) /// ``` /// -/// ## Parameters -/// - value: `i64` (positional, required) -/// The number to check for evenness. -/// -/// - returns: boolean -/// /// Display: Even /// Category: calculate +/// Returns: boolean #[func] -pub fn even(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Bool(args.expect::<i64>("value")? % 2 == 0)) +pub fn even( + /// The number to check for evenness. + value: i64, +) -> Value { + Value::Bool(value % 2 == 0) } /// Determine whether an integer is odd. @@ -589,18 +580,15 @@ pub fn even(args: &mut Args) -> SourceResult<Value> { /// #range(10).filter(calc.odd) /// ``` /// -/// -/// ## Parameters -/// - value: `i64` (positional, required) -/// The number to check for oddness. -/// -/// - returns: boolean -/// /// Display: Odd /// Category: calculate +/// Returns: boolean #[func] -pub fn odd(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Bool(args.expect::<i64>("value")? % 2 != 0)) +pub fn odd( + /// The number to check for oddness. + value: i64, +) -> Value { + Value::Bool(value % 2 != 0) } /// Calculate the modulus of two numbers. @@ -611,25 +599,20 @@ pub fn odd(args: &mut Args) -> SourceResult<Value> { /// #calc.mod(1.75, 0.5) /// ``` /// -/// ## Parameters -/// - dividend: `Num` (positional, required) -/// The dividend of the modulus. -/// -/// - divisor: `Num` (positional, required) -/// The divisor of the modulus. -/// -/// - returns: integer or float -/// /// Display: Modulus /// Category: calculate +/// Returns: integer or float #[func] -pub fn mod_(args: &mut Args) -> SourceResult<Value> { - let dividend = args.expect::<Num>("dividend")?; - let Spanned { v: divisor, span } = args.expect::<Spanned<Num>>("divisor")?; - if divisor.float() == 0.0 { - bail!(span, "divisor must not be zero"); +pub fn mod_( + /// The dividend of the modulus. + dividend: Num, + /// The divisor of the modulus. + divisor: Spanned<Num>, +) -> Value { + if divisor.v.float() == 0.0 { + bail!(divisor.span, "divisor must not be zero"); } - Ok(dividend.apply2(divisor, Rem::rem, Rem::rem)) + dividend.apply2(divisor.v, Rem::rem, Rem::rem) } /// A value which can be passed to functions that work with integers and floats. diff --git a/library/src/compute/construct.rs b/library/src/compute/construct.rs index db442327..4d6068a1 100644 --- a/library/src/compute/construct.rs +++ b/library/src/compute/construct.rs @@ -1,3 +1,4 @@ +use std::num::NonZeroI64; use std::str::FromStr; use ecow::EcoVec; @@ -19,17 +20,15 @@ use crate::prelude::*; /// #{ int("27") + int("4") } /// ``` /// -/// ## Parameters -/// - value: `ToInt` (positional, required) -/// The value that should be converted to an integer. -/// -/// - returns: integer -/// /// Display: Integer /// Category: construct +/// Returns: integer #[func] -pub fn int(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Int(args.expect::<ToInt>("value")?.0)) +pub fn int( + /// The value that should be converted to an integer. + value: ToInt, +) -> Value { + Value::Int(value.0) } /// A value that can be cast to an integer. @@ -59,17 +58,15 @@ cast_from_value! { /// #float("1e5") /// ``` /// -/// ## Parameters -/// - value: `ToFloat` (positional, required) -/// The value that should be converted to a float. -/// -/// - returns: float -/// /// Display: Float /// Category: construct +/// Returns: float #[func] -pub fn float(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Float(args.expect::<ToFloat>("value")?.0)) +pub fn float( + /// The value that should be converted to a float. + value: ToFloat, +) -> Value { + Value::Float(value.0) } /// A value that can be cast to a float. @@ -92,18 +89,15 @@ cast_from_value! { /// } /// ``` /// -/// ## Parameters -/// - gray: `Component` (positional, required) -/// The gray component. -/// -/// - returns: color -/// /// Display: Luma /// Category: construct +/// Returns: color #[func] -pub fn luma(args: &mut Args) -> SourceResult<Value> { - let Component(luma) = args.expect("gray component")?; - Ok(Value::Color(LumaColor::new(luma).into())) +pub fn luma( + /// The gray component. + gray: Component, +) -> Value { + Value::Color(LumaColor::new(gray.0).into()) } /// Create an RGB(A) color. @@ -121,40 +115,44 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> { /// #square(fill: rgb(25%, 13%, 65%)) /// ``` /// -/// ## Parameters -/// - hex: `EcoString` (positional) -/// The color in hexadecimal notation. -/// -/// Accepts three, four, six or eight hexadecimal digits and optionally -/// a leading hashtag. -/// -/// If this string is given, the individual components should not be given. -/// -/// ```example -/// #text(16pt, rgb("#239dad"))[ -/// *Typst* -/// ] -/// ``` -/// -/// - red: `Component` (positional) -/// The red component. -/// -/// - green: `Component` (positional) -/// The green component. -/// -/// - blue: `Component` (positional) -/// The blue component. -/// -/// - alpha: `Component` (positional) -/// The alpha component. -/// -/// - returns: color -/// -/// Display: RGBA +/// Display: RGB /// Category: construct +/// Returns: color #[func] -pub fn rgb(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? { +pub fn rgb( + /// The color in hexadecimal notation. + /// + /// Accepts three, four, six or eight hexadecimal digits and optionally + /// a leading hashtag. + /// + /// If this string is given, the individual components should not be given. + /// + /// ```example + /// #text(16pt, rgb("#239dad"))[ + /// *Typst* + /// ] + /// ``` + #[external] + #[default] + hex: EcoString, + /// The red component. + #[external] + #[default] + red: Component, + /// The green component. + #[external] + #[default] + green: Component, + /// The blue component. + #[external] + #[default] + blue: Component, + /// The alpha component. + #[external] + #[default] + alpha: Component, +) -> Value { + Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? { match RgbaColor::from_str(&string.v) { Ok(color) => color.into(), Err(msg) => bail!(string.span, msg), @@ -165,7 +163,7 @@ pub fn rgb(args: &mut Args) -> SourceResult<Value> { let Component(b) = args.expect("blue component")?; let Component(a) = args.eat()?.unwrap_or(Component(255)); RgbaColor::new(r, g, b, a).into() - })) + }) } /// An integer or ratio component. @@ -197,30 +195,21 @@ cast_from_value! { /// ) /// ```` /// -/// ## Parameters -/// - cyan: `RatioComponent` (positional, required) -/// The cyan component. -/// -/// - magenta: `RatioComponent` (positional, required) -/// The magenta component. -/// -/// - yellow: `RatioComponent` (positional, required) -/// The yellow component. -/// -/// - key: `RatioComponent` (positional, required) -/// The key component. -/// -/// - returns: color -/// /// Display: CMYK /// Category: construct +/// Returns: color #[func] -pub fn cmyk(args: &mut Args) -> SourceResult<Value> { - let RatioComponent(c) = args.expect("cyan component")?; - let RatioComponent(m) = args.expect("magenta component")?; - let RatioComponent(y) = args.expect("yellow component")?; - let RatioComponent(k) = args.expect("key component")?; - Ok(Value::Color(CmykColor::new(c, m, y, k).into())) +pub fn cmyk( + /// The cyan component. + cyan: RatioComponent, + /// The magenta component. + magenta: RatioComponent, + /// The yellow component. + yellow: RatioComponent, + /// The key component. + key: RatioComponent, +) -> Value { + Value::Color(CmykColor::new(cyan.0, magenta.0, yellow.0, key.0).into()) } /// A component that must be a ratio. @@ -254,30 +243,29 @@ cast_from_value! { /// #envelope.fly /// ``` /// -/// ## Parameters -/// - variants: `Variant` (positional, variadic) -/// The variants of the symbol. -/// -/// Can be a just a string consisting of a single character for the -/// modifierless variant or an array with two strings specifying the modifiers -/// and the symbol. Individual modifiers should be separated by dots. When -/// displaying a symbol, Typst selects the first from the variants that have -/// all attached modifiers and the minimum number of other modifiers. -/// -/// - returns: symbol -/// /// Display: Symbol /// Category: construct +/// Returns: symbol #[func] -pub fn symbol(args: &mut Args) -> SourceResult<Value> { +pub fn symbol( + /// The variants of the symbol. + /// + /// Can be a just a string consisting of a single character for the + /// modifierless variant or an array with two strings specifying the modifiers + /// and the symbol. Individual modifiers should be separated by dots. When + /// displaying a symbol, Typst selects the first from the variants that have + /// all attached modifiers and the minimum number of other modifiers. + #[variadic] + variants: Vec<Spanned<Variant>>, +) -> Value { let mut list = EcoVec::new(); - for Spanned { v, span } in args.all::<Spanned<Variant>>()? { + for Spanned { v, span } in variants { if list.iter().any(|(prev, _)| &v.0 == prev) { bail!(span, "duplicate variant"); } list.push((v.0, v.1)); } - Ok(Value::Symbol(Symbol::runtime(list))) + Value::Symbol(Symbol::runtime(list)) } /// A value that can be cast to a symbol. @@ -309,17 +297,15 @@ cast_from_value! { /// #str(<intro>) /// ``` /// -/// ## Parameters -/// - value: `ToStr` (positional, required) -/// The value that should be converted to a string. -/// -/// - returns: string -/// /// Display: String /// Category: construct +/// Returns: string #[func] -pub fn str(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Str(args.expect::<ToStr>("value")?.0)) +pub fn str( + /// The value that should be converted to a string. + value: ToStr, +) -> Value { + Value::Str(value.0) } /// A value that can be cast to a string. @@ -352,17 +338,15 @@ cast_from_value! { /// This function also has dedicated syntax: You can create a label by enclosing /// its name in angle brackets. This works both in markup and code. /// -/// ## Parameters -/// - name: `EcoString` (positional, required) -/// The name of the label. -/// -/// - returns: label -/// /// Display: Label /// Category: construct +/// Returns: label #[func] -pub fn label(args: &mut Args) -> SourceResult<Value> { - Ok(Value::Label(Label(args.expect("string")?))) +pub fn label( + /// The name of the label. + name: EcoString, +) -> Value { + Value::Label(Label(name)) } /// Create a regular expression from a string. @@ -386,23 +370,20 @@ pub fn label(args: &mut Args) -> SourceResult<Value> { /// .split(regex("[,;]"))) /// ``` /// -/// ## Parameters -/// - regex: `EcoString` (positional, required) -/// The regular expression as a string. -/// -/// Most regex escape sequences just work because they are not valid Typst -/// escape sequences. To produce regex escape sequences that are also valid in -/// Typst (e.g. `[\\]`), you need to escape twice. Thus, to match a verbatim -/// backslash, you would need to write `{regex("\\\\")}`. -/// -/// - returns: regex -/// /// Display: Regex /// Category: construct +/// Returns: regex #[func] -pub fn regex(args: &mut Args) -> SourceResult<Value> { - let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?; - Ok(Regex::new(&v).at(span)?.into()) +pub fn regex( + /// The regular expression as a string. + /// + /// Most regex escape sequences just work because they are not valid Typst + /// escape sequences. To produce regex escape sequences that are also valid in + /// Typst (e.g. `[\\]`), you need to escape twice. Thus, to match a verbatim + /// backslash, you would need to write `{regex("\\\\")}`. + regex: Spanned<EcoString>, +) -> Value { + Regex::new(®ex.v).at(regex.span)?.into() } /// Create an array consisting of a sequence of numbers. @@ -420,33 +401,30 @@ pub fn regex(args: &mut Args) -> SourceResult<Value> { /// #range(5, 2, step: -1) /// ``` /// -/// ## Parameters -/// - start: `i64` (positional) -/// The start of the range (inclusive). -/// -/// - end: `i64` (positional, required) -/// The end of the range (exclusive). -/// -/// - step: `i64` (named) -/// The distance between the generated numbers. -/// -/// - returns: array -/// /// Display: Range /// Category: construct +/// Returns: array #[func] -pub fn range(args: &mut Args) -> SourceResult<Value> { +pub fn range( + /// The start of the range (inclusive). + #[external] + #[default] + start: i64, + /// The end of the range (exclusive). + #[external] + end: i64, + /// The distance between the generated numbers. + #[named] + #[default(NonZeroI64::new(1).unwrap())] + step: NonZeroI64, +) -> Value { let first = args.expect::<i64>("end")?; let (start, end) = match args.eat::<i64>()? { Some(second) => (first, second), None => (0, first), }; - let step: i64 = match args.named("step")? { - Some(Spanned { v: 0, span }) => bail!(span, "step must not be zero"), - Some(Spanned { v, .. }) => v, - None => 1, - }; + let step = step.get(); let mut x = start; let mut array = Array::new(); @@ -456,5 +434,5 @@ pub fn range(args: &mut Args) -> SourceResult<Value> { x += step; } - Ok(Value::Array(array)) + Value::Array(array) } diff --git a/library/src/compute/data.rs b/library/src/compute/data.rs index 90d72ade..7addff78 100644 --- a/library/src/compute/data.rs +++ b/library/src/compute/data.rs @@ -16,25 +16,21 @@ use crate::prelude::*; /// #raw(text, lang: "html") /// ``` /// -/// ## Parameters -/// - path: `EcoString` (positional, required) -/// Path to a file. -/// -/// - returns: string -/// /// Display: Plain text /// Category: data-loading +/// Returns: string #[func] -pub fn read(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to file")?; - +pub fn read( + /// Path to a file. + path: Spanned<EcoString>, +) -> Value { + let Spanned { v: path, span } = path; let path = vm.locate(&path).at(span)?; let data = vm.world().file(&path).at(span)?; - let text = String::from_utf8(data.to_vec()) .map_err(|_| "file is not valid utf-8") .at(span)?; - Ok(Value::Str(text.into())) + Value::Str(text.into()) } /// Read structured data from a CSV file. @@ -55,33 +51,27 @@ pub fn read(vm: &Vm, args: &mut Args) -> SourceResult<Value> { /// ) /// ``` /// -/// ## Parameters -/// - path: `EcoString` (positional, required) -/// Path to a CSV file. -/// -/// - delimiter: `Delimiter` (named) -/// The delimiter that separates columns in the CSV file. -/// Must be a single ASCII character. -/// Defaults to a comma. -/// -/// - returns: array -/// /// Display: CSV /// Category: data-loading +/// Returns: array #[func] -pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let Spanned { v: path, span } = - args.expect::<Spanned<EcoString>>("path to csv file")?; - +pub fn csv( + /// Path to a CSV file. + path: Spanned<EcoString>, + /// The delimiter that separates columns in the CSV file. + /// Must be a single ASCII character. + /// Defaults to a comma. + #[named] + #[default] + delimiter: Delimiter, +) -> Value { + let Spanned { v: path, span } = path; let path = vm.locate(&path).at(span)?; let data = vm.world().file(&path).at(span)?; let mut builder = csv::ReaderBuilder::new(); builder.has_headers(false); - - if let Some(delimiter) = args.named::<Delimiter>("delimiter")? { - builder.delimiter(delimiter.0); - } + builder.delimiter(delimiter.0); let mut reader = builder.from_reader(data.as_slice()); let mut array = Array::new(); @@ -92,7 +82,7 @@ pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> { array.push(Value::Array(sub)) } - Ok(Value::Array(array)) + Value::Array(array) } /// The delimiter to use when parsing CSV files. @@ -115,6 +105,12 @@ cast_from_value! { }, } +impl Default for Delimiter { + fn default() -> Self { + Self(b',') + } +} + /// Format the user-facing CSV error message. fn format_csv_error(error: csv::Error) -> String { match error.kind() { @@ -170,25 +166,20 @@ fn format_csv_error(error: csv::Error) -> String { /// #forecast(json("tuesday.json")) /// ``` /// -/// ## Parameters -/// - path: `EcoString` (positional, required) -/// Path to a JSON file. -/// -/// - returns: dictionary or array -/// /// Display: JSON /// Category: data-loading +/// Returns: array or dictionary #[func] -pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let Spanned { v: path, span } = - args.expect::<Spanned<EcoString>>("path to json file")?; - +pub fn json( + /// Path to a JSON file. + path: Spanned<EcoString>, +) -> Value { + let Spanned { v: path, span } = path; let path = vm.locate(&path).at(span)?; let data = vm.world().file(&path).at(span)?; let value: serde_json::Value = serde_json::from_slice(&data).map_err(format_json_error).at(span)?; - - Ok(convert_json(value)) + convert_json(value) } /// Convert a JSON value to a Typst value. @@ -268,26 +259,20 @@ fn format_json_error(error: serde_json::Error) -> String { /// } /// ``` /// -/// ## Parameters -/// - path: `EcoString` (positional, required) -/// Path to an XML file. -/// -/// - returns: array -/// /// Display: XML /// Category: data-loading +/// Returns: array #[func] -pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let Spanned { v: path, span } = - args.expect::<Spanned<EcoString>>("path to xml file")?; - +pub fn xml( + /// Path to an XML file. + path: Spanned<EcoString>, +) -> Value { + let Spanned { v: path, span } = path; let path = vm.locate(&path).at(span)?; let data = vm.world().file(&path).at(span)?; let text = std::str::from_utf8(&data).map_err(FileError::from).at(span)?; - let document = roxmltree::Document::parse(text).map_err(format_xml_error).at(span)?; - - Ok(convert_xml(document.root())) + convert_xml(document.root()) } /// Convert an XML node to a Typst value. diff --git a/library/src/compute/foundations.rs b/library/src/compute/foundations.rs index 710ec68e..41a6bc35 100644 --- a/library/src/compute/foundations.rs +++ b/library/src/compute/foundations.rs @@ -14,17 +14,15 @@ use crate::prelude::*; /// #type(x => x + 1) /// ``` /// -/// ## Parameters -/// - value: `Value` (positional, required) -/// The value whose type's to determine. -/// -/// - returns: string -/// /// Display: Type /// Category: foundations +/// Returns: string #[func] -pub fn type_(args: &mut Args) -> SourceResult<Value> { - Ok(args.expect::<Value>("value")?.type_name().into()) +pub fn type_( + /// The value whose type's to determine. + value: Value, +) -> Value { + value.type_name().into() } /// The string representation of a value. @@ -41,17 +39,15 @@ pub fn type_(args: &mut Args) -> SourceResult<Value> { /// #[*Hi*] vs #repr([*Hi*]) /// ``` /// -/// ## Parameters -/// - value: `Value` (positional, required) -/// The value whose string representation to produce. -/// -/// - returns: string -/// /// Display: Representation /// Category: foundations +/// Returns: string #[func] -pub fn repr(args: &mut Args) -> SourceResult<Value> { - Ok(args.expect::<Value>("value")?.repr().into()) +pub fn repr( + /// The value whose string representation to produce. + value: Value, +) -> Value { + value.repr().into() } /// Fail with an error. @@ -62,15 +58,16 @@ pub fn repr(args: &mut Args) -> SourceResult<Value> { /// #panic("this is wrong") /// ``` /// -/// ## Parameters -/// - payload: `Value` (positional) -/// The value (or message) to panic with. -/// /// Display: Panic /// Category: foundations +/// Returns: #[func] -pub fn panic(args: &mut Args) -> SourceResult<Value> { - match args.eat::<Value>()? { +pub fn panic( + /// The value (or message) to panic with. + #[default] + payload: Option<Value>, +) -> Value { + match payload { Some(v) => bail!(args.span, "panicked with: {}", v.repr()), None => bail!(args.span, "panicked"), } @@ -86,26 +83,26 @@ pub fn panic(args: &mut Args) -> SourceResult<Value> { /// #assert(1 < 2, message: "math broke") /// ``` /// -/// ## Parameters -/// - condition: `bool` (positional, required) -/// The condition that must be true for the assertion to pass. -/// - message: `EcoString` (named) -/// The error message when the assertion fails. -/// /// Display: Assert /// Category: foundations +/// Returns: #[func] -pub fn assert(args: &mut Args) -> SourceResult<Value> { - let check = args.expect::<bool>("condition")?; - let message = args.named::<EcoString>("message")?; - if !check { +pub fn assert( + /// The condition that must be true for the assertion to pass. + condition: bool, + /// The error message when the assertion fails. + #[named] + #[default] + message: Option<EcoString>, +) -> Value { + if !condition { if let Some(message) = message { bail!(args.span, "assertion failed: {}", message); } else { bail!(args.span, "assertion failed"); } } - Ok(Value::None) + Value::None } /// Evaluate a string as Typst code. @@ -119,18 +116,16 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> { /// #eval("[*Strong text*]") /// ``` /// -/// ## Parameters -/// - source: `String` (positional, required) -/// A string of Typst code to evaluate. -/// -/// The code in the string cannot interact with the file system. -/// -/// - returns: any -/// /// Display: Evaluate /// Category: foundations +/// Returns: any #[func] -pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; - typst::eval::eval_code_str(vm.world(), &text, span) +pub fn eval( + /// A string of Typst code to evaluate. + /// + /// The code in the string cannot interact with the file system. + source: Spanned<String>, +) -> Value { + let Spanned { v: text, span } = source; + typst::eval::eval_code_str(vm.world(), &text, span)? } diff --git a/library/src/layout/align.rs b/library/src/layout/align.rs index 88815dc9..cf6d08f2 100644 --- a/library/src/layout/align.rs +++ b/library/src/layout/align.rs @@ -53,7 +53,6 @@ pub struct AlignNode { pub alignment: Axes<Option<GenAlign>>, /// The content to align. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/columns.rs b/library/src/layout/columns.rs index 58b369c6..7704e9c4 100644 --- a/library/src/layout/columns.rs +++ b/library/src/layout/columns.rs @@ -45,7 +45,6 @@ pub struct ColumnsNode { pub gutter: Rel<Length>, /// The content that should be layouted into the columns. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs index 31a80aa2..009063f0 100644 --- a/library/src/layout/container.rs +++ b/library/src/layout/container.rs @@ -181,20 +181,6 @@ impl Layout for BoxNode { /// More text. /// ``` /// -/// ## Parameters -/// - spacing: `Spacing` (named, settable) -/// The spacing around this block. This is shorthand to set `above` and -/// `below` to the same value. -/// -/// ```example -/// #set align(center) -/// #show math.formula: set block(above: 8pt, below: 16pt) -/// -/// This sum of $x$ and $y$: -/// $ x + y = z $ -/// A second paragraph. -/// ``` -/// /// Display: Block /// Category: layout #[node(Layout)] @@ -270,6 +256,20 @@ pub struct BlockNode { #[fold] pub outset: Sides<Option<Rel<Length>>>, + /// The spacing around this block. This is shorthand to set `above` and + /// `below` to the same value. + /// + /// ```example + /// #set align(center) + /// #show math.formula: set block(above: 8pt, below: 16pt) + /// + /// This sum of $x$ and $y$: + /// $ x + y = z $ + /// A second paragraph. + /// ``` + #[external] + pub spacing: Spacing, + /// The spacing between this block and its predecessor. Takes precedence /// over `spacing`. Can be used in combination with a show rule to adjust /// the spacing around arbitrary block-level elements. diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs index ee09d339..33b297e7 100644 --- a/library/src/layout/enum.rs +++ b/library/src/layout/enum.rs @@ -228,7 +228,6 @@ pub struct EnumItem { pub number: Option<NonZeroUsize>, /// The item's body. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs index 34514eac..b6e86afd 100644 --- a/library/src/layout/grid.rs +++ b/library/src/layout/grid.rs @@ -59,12 +59,6 @@ use super::Sizing; /// ) /// ``` /// -/// ## Parameters -/// - gutter: `TrackSizings` (named, settable) -/// Defines the gaps between rows & columns. -/// -/// If there are more gutters than defined sizes, the last gutter is repeated. -/// /// Display: Grid /// Category: layout #[node(Layout)] @@ -83,6 +77,12 @@ pub struct GridNode { /// repeated until there are no more cells. pub rows: TrackSizings, + /// Defines the gaps between rows & columns. + /// + /// If there are more gutters than defined sizes, the last gutter is repeated. + #[external] + pub gutter: TrackSizings, + /// Defines the gaps between columns. Takes precedence over `gutter`. #[parse( let gutter = args.named("gutter")?; diff --git a/library/src/layout/hide.rs b/library/src/layout/hide.rs index 43d9a2a8..62628445 100644 --- a/library/src/layout/hide.rs +++ b/library/src/layout/hide.rs @@ -18,7 +18,6 @@ use crate::prelude::*; #[node(Show)] pub struct HideNode { /// The content to hide. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/list.rs b/library/src/layout/list.rs index 57b653c0..6d605868 100644 --- a/library/src/layout/list.rs +++ b/library/src/layout/list.rs @@ -163,7 +163,6 @@ impl Layout for ListNode { #[node] pub struct ListItem { /// The item's body. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/pad.rs b/library/src/layout/pad.rs index 7d0bbe04..e8171560 100644 --- a/library/src/layout/pad.rs +++ b/library/src/layout/pad.rs @@ -15,16 +15,6 @@ use crate::prelude::*; /// measured in words per minute._ /// ``` /// -/// ## Parameters -/// - x: `Rel<Length>` (named, settable) -/// The horizontal padding. Both `left` and `right` take precedence over this. -/// -/// - y: `Rel<Length>` (named, settable) -/// The vertical padding. Both `top` and `bottom` take precedence over this. -/// -/// - rest: `Rel<Length>` (named, settable) -/// The padding for all sides. All other parameters take precedence over this. -/// /// Display: Padding /// Category: layout #[node(Layout)] @@ -50,8 +40,21 @@ pub struct PadNode { #[parse(args.named("bottom")?.or(y))] pub bottom: Rel<Length>, + /// The horizontal padding. Both `left` and `right` take precedence over + /// this. + #[external] + pub x: Rel<Length>, + + /// The vertical padding. Both `top` and `bottom` take precedence over this. + #[external] + pub y: Rel<Length>, + + /// The padding for all sides. All other parameters take precedence over + /// this. + #[external] + pub rest: Rel<Length>, + /// The content to pad at the sides. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs index 5fe3c90a..e469bf10 100644 --- a/library/src/layout/page.rs +++ b/library/src/layout/page.rs @@ -20,15 +20,15 @@ use crate::prelude::*; /// There you go, US friends! /// ``` /// -/// ## Parameters -/// - paper: `Paper` (positional, named, settable) -/// A standard paper size to set width and height. When this is not specified, -/// Typst defaults to `{"a4"}` paper. -/// /// Display: Page /// Category: layout #[node] pub struct PageNode { + /// A standard paper size to set width and height. When this is not + /// specified, Typst defaults to `{"a4"}` paper. + #[external] + pub paper: Paper, + /// The width of the page. /// /// ```example @@ -232,7 +232,6 @@ pub struct PageNode { /// Multiple pages will be created if the content does not fit on a single /// page. A new page with the page properties prior to the function invocation /// will be created after the body has been typeset. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index 93cca452..e5644a2e 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -35,10 +35,6 @@ use crate::text::{ /// three integers. Then, we ... /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// The contents of the paragraph. -/// /// Display: Paragraph /// Category: layout #[node(Construct)] @@ -99,6 +95,10 @@ pub struct ParNode { #[default] pub linebreaks: Smart<Linebreaks>, + /// The contents of the paragraph. + #[external] + pub body: Content, + /// The paragraph's children. #[internal] #[variadic] diff --git a/library/src/layout/place.rs b/library/src/layout/place.rs index 8d7aa229..bfabd0f3 100644 --- a/library/src/layout/place.rs +++ b/library/src/layout/place.rs @@ -49,7 +49,6 @@ pub struct PlaceNode { pub dy: Rel<Length>, /// The content to place. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/repeat.rs b/library/src/layout/repeat.rs index 0fd9ad83..c8f63ac3 100644 --- a/library/src/layout/repeat.rs +++ b/library/src/layout/repeat.rs @@ -26,7 +26,6 @@ use super::AlignNode; #[node(Layout)] pub struct RepeatNode { /// The content to repeat. - #[positional] #[required] pub body: Content, } diff --git a/library/src/layout/spacing.rs b/library/src/layout/spacing.rs index c11a2f06..dbdf0c11 100644 --- a/library/src/layout/spacing.rs +++ b/library/src/layout/spacing.rs @@ -24,7 +24,6 @@ use crate::prelude::*; #[node(Behave)] pub struct HNode { /// How much spacing to insert. - #[positional] #[required] pub amount: Spacing, @@ -84,31 +83,30 @@ impl Behave for HNode { /// ) /// ``` /// -/// ## Parameters -/// - weak: `bool` (named, settable) -/// If true, the spacing collapses at the start or end of a flow. Moreover, -/// from multiple adjacent weak spacings all but the largest one collapse. -/// Weak spacings will always collapse adjacent paragraph spacing, even if the -/// paragraph spacing is larger. -/// -/// ```example -/// The following theorem is -/// foundational to the field: -/// #v(4pt, weak: true) -/// $ x^2 + y^2 = r^2 $ -/// #v(4pt, weak: true) -/// The proof is simple: -/// ``` -/// /// Display: Spacing (V) /// Category: layout #[node(Behave)] pub struct VNode { /// How much spacing to insert. - #[positional] #[required] pub amount: Spacing, + /// If true, the spacing collapses at the start or end of a flow. Moreover, + /// from multiple adjacent weak spacings all but the largest one collapse. + /// Weak spacings will always collapse adjacent paragraph spacing, even if the + /// paragraph spacing is larger. + /// + /// ```example + /// The following theorem is + /// foundational to the field: + /// #v(4pt, weak: true) + /// $ x^2 + y^2 = r^2 $ + /// #v(4pt, weak: true) + /// The proof is simple: + /// ``` + #[external] + pub weak: bool, + /// The node's weakness level, see also [`Behaviour`]. #[internal] #[parse(args.named("weak")?.map(|v: bool| v as usize))] diff --git a/library/src/layout/table.rs b/library/src/layout/table.rs index 59635119..fabe8c33 100644 --- a/library/src/layout/table.rs +++ b/library/src/layout/table.rs @@ -29,35 +29,33 @@ use crate::prelude::*; /// ) /// ``` /// -/// ## Parameters -/// - gutter: `TrackSizings` (named, settable) -/// Defines the gaps between rows & columns. -/// See the [grid documentation]($func/grid) for more information on gutters. -/// /// Display: Table /// Category: layout #[node(Layout)] pub struct TableNode { - /// Defines the column sizes. - /// See the [grid documentation]($func/grid) for more information on track - /// sizing. + /// Defines the column sizes. See the [grid documentation]($func/grid) for + /// more information on track sizing. pub columns: TrackSizings, - /// Defines the row sizes. - /// See the [grid documentation]($func/grid) for more information on track - /// sizing. + /// Defines the row sizes. See the [grid documentation]($func/grid) for more + /// information on track sizing. pub rows: TrackSizings, - /// Defines the gaps between columns. Takes precedence over `gutter`. - /// See the [grid documentation]($func/grid) for more information on gutters. + /// Defines the gaps between rows & columns. See the [grid + /// documentation]($func/grid) for more information on gutters. + #[external] + pub gutter: TrackSizings, + + /// Defines the gaps between columns. Takes precedence over `gutter`. See + /// the [grid documentation]($func/grid) for more information on gutters. #[parse( let gutter = args.named("gutter")?; args.named("column-gutter")?.or_else(|| gutter.clone()) )] pub column_gutter: TrackSizings, - /// Defines the gaps between rows. Takes precedence over `gutter`. - /// See the [grid documentation]($func/grid) for more information on gutters. + /// Defines the gaps between rows. Takes precedence over `gutter`. See the + /// [grid documentation]($func/grid) for more information on gutters. #[parse(args.named("row-gutter")?.or_else(|| gutter.clone()))] pub row_gutter: TrackSizings, diff --git a/library/src/layout/terms.rs b/library/src/layout/terms.rs index 8ab4edc6..b2f45446 100644 --- a/library/src/layout/terms.rs +++ b/library/src/layout/terms.rs @@ -126,12 +126,10 @@ impl Layout for TermsNode { #[node] pub struct TermItem { /// The term described by the list item. - #[positional] #[required] pub term: Content, /// The description of the term. - #[positional] #[required] pub description: Content, } diff --git a/library/src/layout/transform.rs b/library/src/layout/transform.rs index 4521da32..2afe8201 100644 --- a/library/src/layout/transform.rs +++ b/library/src/layout/transform.rs @@ -32,7 +32,6 @@ pub struct MoveNode { pub dy: Rel<Length>, /// The content to move. - #[positional] #[required] pub body: Content, } @@ -101,7 +100,6 @@ pub struct RotateNode { pub origin: Axes<Option<GenAlign>>, /// The content to rotate. - #[positional] #[required] pub body: Content, } @@ -170,7 +168,6 @@ pub struct ScaleNode { pub origin: Axes<Option<GenAlign>>, /// The content to scale. - #[positional] #[required] pub body: Content, } diff --git a/library/src/lib.rs b/library/src/lib.rs index bcbd703d..ad8a2ac4 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -29,91 +29,91 @@ fn global(math: Module, calc: Module) -> Module { let mut global = Scope::deduplicating(); // Text. - global.def_func::<text::TextNode>("text"); - global.def_func::<text::LinebreakNode>("linebreak"); - global.def_func::<text::SmartQuoteNode>("smartquote"); - global.def_func::<text::StrongNode>("strong"); - global.def_func::<text::EmphNode>("emph"); - global.def_func::<text::LowerFunc>("lower"); - global.def_func::<text::UpperFunc>("upper"); - global.def_func::<text::SmallcapsFunc>("smallcaps"); - global.def_func::<text::SubNode>("sub"); - global.def_func::<text::SuperNode>("super"); - global.def_func::<text::UnderlineNode>("underline"); - global.def_func::<text::StrikeNode>("strike"); - global.def_func::<text::OverlineNode>("overline"); - global.def_func::<text::RawNode>("raw"); - global.def_func::<text::LoremFunc>("lorem"); + global.define("text", text::TextNode::func()); + global.define("linebreak", text::LinebreakNode::func()); + global.define("smartquote", text::SmartQuoteNode::func()); + global.define("strong", text::StrongNode::func()); + global.define("emph", text::EmphNode::func()); + global.define("lower", text::lower); + global.define("upper", text::upper); + global.define("smallcaps", text::smallcaps); + global.define("sub", text::SubNode::func()); + global.define("super", text::SuperNode::func()); + global.define("underline", text::UnderlineNode::func()); + global.define("strike", text::StrikeNode::func()); + global.define("overline", text::OverlineNode::func()); + global.define("raw", text::RawNode::func()); + global.define("lorem", text::lorem); // Math. global.define("math", math); // Layout. - global.def_func::<layout::PageNode>("page"); - global.def_func::<layout::PagebreakNode>("pagebreak"); - global.def_func::<layout::VNode>("v"); - global.def_func::<layout::ParNode>("par"); - global.def_func::<layout::ParbreakNode>("parbreak"); - global.def_func::<layout::HNode>("h"); - global.def_func::<layout::BoxNode>("box"); - global.def_func::<layout::BlockNode>("block"); - global.def_func::<layout::ListNode>("list"); - global.def_func::<layout::EnumNode>("enum"); - global.def_func::<layout::TermsNode>("terms"); - global.def_func::<layout::TableNode>("table"); - global.def_func::<layout::StackNode>("stack"); - global.def_func::<layout::GridNode>("grid"); - global.def_func::<layout::ColumnsNode>("columns"); - global.def_func::<layout::ColbreakNode>("colbreak"); - global.def_func::<layout::PlaceNode>("place"); - global.def_func::<layout::AlignNode>("align"); - global.def_func::<layout::PadNode>("pad"); - global.def_func::<layout::RepeatNode>("repeat"); - global.def_func::<layout::MoveNode>("move"); - global.def_func::<layout::ScaleNode>("scale"); - global.def_func::<layout::RotateNode>("rotate"); - global.def_func::<layout::HideNode>("hide"); + global.define("page", layout::PageNode::func()); + global.define("pagebreak", layout::PagebreakNode::func()); + global.define("v", layout::VNode::func()); + global.define("par", layout::ParNode::func()); + global.define("parbreak", layout::ParbreakNode::func()); + global.define("h", layout::HNode::func()); + global.define("box", layout::BoxNode::func()); + global.define("block", layout::BlockNode::func()); + global.define("list", layout::ListNode::func()); + global.define("enum", layout::EnumNode::func()); + global.define("terms", layout::TermsNode::func()); + global.define("table", layout::TableNode::func()); + global.define("stack", layout::StackNode::func()); + global.define("grid", layout::GridNode::func()); + global.define("columns", layout::ColumnsNode::func()); + global.define("colbreak", layout::ColbreakNode::func()); + global.define("place", layout::PlaceNode::func()); + global.define("align", layout::AlignNode::func()); + global.define("pad", layout::PadNode::func()); + global.define("repeat", layout::RepeatNode::func()); + global.define("move", layout::MoveNode::func()); + global.define("scale", layout::ScaleNode::func()); + global.define("rotate", layout::RotateNode::func()); + global.define("hide", layout::HideNode::func()); // Visualize. - global.def_func::<visualize::ImageNode>("image"); - global.def_func::<visualize::LineNode>("line"); - global.def_func::<visualize::RectNode>("rect"); - global.def_func::<visualize::SquareNode>("square"); - global.def_func::<visualize::EllipseNode>("ellipse"); - global.def_func::<visualize::CircleNode>("circle"); + global.define("image", visualize::ImageNode::func()); + global.define("line", visualize::LineNode::func()); + global.define("rect", visualize::RectNode::func()); + global.define("square", visualize::SquareNode::func()); + global.define("ellipse", visualize::EllipseNode::func()); + global.define("circle", visualize::CircleNode::func()); // Meta. - global.def_func::<meta::DocumentNode>("document"); - global.def_func::<meta::RefNode>("ref"); - global.def_func::<meta::LinkNode>("link"); - global.def_func::<meta::OutlineNode>("outline"); - global.def_func::<meta::HeadingNode>("heading"); - global.def_func::<meta::NumberingFunc>("numbering"); + global.define("document", meta::DocumentNode::func()); + global.define("ref", meta::RefNode::func()); + global.define("link", meta::LinkNode::func()); + global.define("outline", meta::OutlineNode::func()); + global.define("heading", meta::HeadingNode::func()); + global.define("numbering", meta::numbering); // Symbols. global.define("sym", symbols::sym()); global.define("emoji", symbols::emoji()); // Compute. - global.def_func::<compute::TypeFunc>("type"); - global.def_func::<compute::ReprFunc>("repr"); - global.def_func::<compute::PanicFunc>("panic"); - global.def_func::<compute::AssertFunc>("assert"); - global.def_func::<compute::EvalFunc>("eval"); - global.def_func::<compute::IntFunc>("int"); - global.def_func::<compute::FloatFunc>("float"); - global.def_func::<compute::LumaFunc>("luma"); - global.def_func::<compute::RgbFunc>("rgb"); - global.def_func::<compute::CmykFunc>("cmyk"); - global.def_func::<compute::SymbolFunc>("symbol"); - global.def_func::<compute::StrFunc>("str"); - global.def_func::<compute::LabelFunc>("label"); - global.def_func::<compute::RegexFunc>("regex"); - global.def_func::<compute::RangeFunc>("range"); - global.def_func::<compute::ReadFunc>("read"); - global.def_func::<compute::CsvFunc>("csv"); - global.def_func::<compute::JsonFunc>("json"); - global.def_func::<compute::XmlFunc>("xml"); + global.define("type", compute::type_); + global.define("repr", compute::repr); + global.define("panic", compute::panic); + global.define("assert", compute::assert); + global.define("eval", compute::eval); + global.define("int", compute::int); + global.define("float", compute::float); + global.define("luma", compute::luma); + global.define("rgb", compute::rgb); + global.define("cmyk", compute::cmyk); + global.define("symbol", compute::symbol); + global.define("str", compute::str); + global.define("label", compute::label); + global.define("regex", compute::regex); + global.define("range", compute::range); + global.define("read", compute::read); + global.define("csv", compute::csv); + global.define("json", compute::json); + global.define("xml", compute::xml); // Calc. global.define("calc", calc); diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index 164247de..03caf411 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -24,7 +24,6 @@ pub struct AccentNode { /// ```example /// $arrow(A B C)$ /// ``` - #[positional] #[required] pub base: Content, @@ -47,7 +46,6 @@ pub struct AccentNode { /// | Caron | `caron` | `ˇ` | /// | Right arrow | `arrow`, `->` | `→` | /// | Left arrow | `arrow.l`, `<-` | `←` | - #[positional] #[required] pub accent: Accent, } diff --git a/library/src/math/attach.rs b/library/src/math/attach.rs index c2d7703d..7d8749f2 100644 --- a/library/src/math/attach.rs +++ b/library/src/math/attach.rs @@ -16,7 +16,6 @@ use super::*; #[node(LayoutMath)] pub struct AttachNode { /// The base to which things are attached. - #[positional] #[required] pub base: Content, @@ -79,7 +78,6 @@ impl LayoutMath for AttachNode { #[node(LayoutMath)] pub struct ScriptsNode { /// The base to attach the scripts to. - #[positional] #[required] pub body: Content, } @@ -102,7 +100,6 @@ impl LayoutMath for ScriptsNode { #[node(LayoutMath)] pub struct LimitsNode { /// The base to attach the limits to. - #[positional] #[required] pub body: Content, } diff --git a/library/src/math/delimited.rs b/library/src/math/delimited.rs index f9d22c43..6f468af7 100644 --- a/library/src/math/delimited.rs +++ b/library/src/math/delimited.rs @@ -24,7 +24,6 @@ pub struct LrNode { pub size: Smart<Rel<Length>>, /// The delimited content, including the delimiters. - #[positional] #[required] #[parse( let mut body = Content::empty(); @@ -111,15 +110,15 @@ fn scale( /// $ floor(x/2) $ /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// The expression to floor. -/// /// Display: Floor /// Category: math +/// Returns: content #[func] -pub fn floor(args: &mut Args) -> SourceResult<Value> { - delimited(args, '⌊', '⌋') +pub fn floor( + /// The expression to floor. + body: Content, +) -> Value { + delimited(body, '⌊', '⌋') } /// Ceil an expression. @@ -129,15 +128,15 @@ pub fn floor(args: &mut Args) -> SourceResult<Value> { /// $ ceil(x/2) $ /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// The expression to ceil. -/// /// Display: Ceil /// Category: math +/// Returns: content #[func] -pub fn ceil(args: &mut Args) -> SourceResult<Value> { - delimited(args, '⌈', '⌉') +pub fn ceil( + /// The expression to ceil. + body: Content, +) -> Value { + delimited(body, '⌈', '⌉') } /// Take the absolute value of an expression. @@ -147,15 +146,16 @@ pub fn ceil(args: &mut Args) -> SourceResult<Value> { /// $ abs(x/2) $ /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// The expression to take the absolute value of. /// /// Display: Abs /// Category: math +/// Returns: content #[func] -pub fn abs(args: &mut Args) -> SourceResult<Value> { - delimited(args, '|', '|') +pub fn abs( + /// The expression to take the absolute value of. + body: Content, +) -> Value { + delimited(body, '|', '|') } /// Take the norm of an expression. @@ -165,24 +165,24 @@ pub fn abs(args: &mut Args) -> SourceResult<Value> { /// $ norm(x/2) $ /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// The expression to take the norm of. -/// /// Display: Norm /// Category: math +/// Returns: content #[func] -pub fn norm(args: &mut Args) -> SourceResult<Value> { - delimited(args, '‖', '‖') +pub fn norm( + /// The expression to take the norm of. + body: Content, +) -> Value { + delimited(body, '‖', '‖') } -fn delimited(args: &mut Args, left: char, right: char) -> SourceResult<Value> { - Ok(Value::Content( +fn delimited(body: Content, left: char, right: char) -> Value { + Value::Content( LrNode::new(Content::sequence(vec![ TextNode::packed(left), - args.expect::<Content>("body")?, + body, TextNode::packed(right), ])) .pack(), - )) + ) } diff --git a/library/src/math/frac.rs b/library/src/math/frac.rs index c1f4065b..0624832a 100644 --- a/library/src/math/frac.rs +++ b/library/src/math/frac.rs @@ -22,12 +22,10 @@ const FRAC_AROUND: Em = Em::new(0.1); #[node(LayoutMath)] pub struct FracNode { /// The fraction's numerator. - #[positional] #[required] pub num: Content, /// The fraction's denominator. - #[positional] #[required] pub denom: Content, } @@ -50,12 +48,10 @@ impl LayoutMath for FracNode { #[node(LayoutMath)] pub struct BinomNode { /// The binomial's upper index. - #[positional] #[required] pub upper: Content, /// The binomial's lower index. - #[positional] #[required] pub lower: Content, } diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 0c9dc338..8f89e028 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -47,52 +47,52 @@ use crate::text::{ /// Create a module with all math definitions. pub fn module() -> Module { let mut math = Scope::deduplicating(); - math.def_func::<FormulaNode>("formula"); - math.def_func::<TextNode>("text"); + math.define("formula", FormulaNode::func()); + math.define("text", TextNode::func()); // Grouping. - math.def_func::<LrNode>("lr"); - math.def_func::<AbsFunc>("abs"); - math.def_func::<NormFunc>("norm"); - math.def_func::<FloorFunc>("floor"); - math.def_func::<CeilFunc>("ceil"); + math.define("lr", LrNode::func()); + math.define("abs", abs); + math.define("norm", norm); + math.define("floor", floor); + math.define("ceil", ceil); // Attachments and accents. - math.def_func::<AttachNode>("attach"); - math.def_func::<ScriptsNode>("scripts"); - math.def_func::<LimitsNode>("limits"); - math.def_func::<AccentNode>("accent"); - math.def_func::<UnderlineNode>("underline"); - math.def_func::<OverlineNode>("overline"); - math.def_func::<UnderbraceNode>("underbrace"); - math.def_func::<OverbraceNode>("overbrace"); - math.def_func::<UnderbracketNode>("underbracket"); - math.def_func::<OverbracketNode>("overbracket"); + math.define("attach", AttachNode::func()); + math.define("scripts", ScriptsNode::func()); + math.define("limits", LimitsNode::func()); + math.define("accent", AccentNode::func()); + math.define("underline", UnderlineNode::func()); + math.define("overline", OverlineNode::func()); + math.define("underbrace", UnderbraceNode::func()); + math.define("overbrace", OverbraceNode::func()); + math.define("underbracket", UnderbracketNode::func()); + math.define("overbracket", OverbracketNode::func()); // Fractions and matrix-likes. - math.def_func::<FracNode>("frac"); - math.def_func::<BinomNode>("binom"); - math.def_func::<VecNode>("vec"); - math.def_func::<MatNode>("mat"); - math.def_func::<CasesNode>("cases"); + math.define("frac", FracNode::func()); + math.define("binom", BinomNode::func()); + math.define("vec", VecNode::func()); + math.define("mat", MatNode::func()); + math.define("cases", CasesNode::func()); // Roots. - math.def_func::<SqrtNode>("sqrt"); - math.def_func::<RootNode>("root"); + math.define("sqrt", SqrtNode::func()); + math.define("root", RootNode::func()); // Styles. - math.def_func::<UprightNode>("upright"); - math.def_func::<BoldNode>("bold"); - math.def_func::<ItalicNode>("italic"); - math.def_func::<SerifNode>("serif"); - math.def_func::<SansNode>("sans"); - math.def_func::<CalNode>("cal"); - math.def_func::<FrakNode>("frak"); - math.def_func::<MonoNode>("mono"); - math.def_func::<BbNode>("bb"); + math.define("upright", UprightNode::func()); + math.define("bold", BoldNode::func()); + math.define("italic", ItalicNode::func()); + math.define("serif", SerifNode::func()); + math.define("sans", SansNode::func()); + math.define("cal", CalNode::func()); + math.define("frak", FrakNode::func()); + math.define("mono", MonoNode::func()); + math.define("bb", BbNode::func()); // Text operators. - math.def_func::<OpNode>("op"); + math.define("op", OpNode::func()); op::define(&mut math); // Spacings. @@ -139,7 +139,6 @@ pub struct FormulaNode { pub block: bool, /// The content of the formula. - #[positional] #[required] pub body: Content, } diff --git a/library/src/math/op.rs b/library/src/math/op.rs index aa2e4cf7..bd81aa0e 100644 --- a/library/src/math/op.rs +++ b/library/src/math/op.rs @@ -23,7 +23,6 @@ use super::*; #[node(LayoutMath)] pub struct OpNode { /// The operator's text. - #[positional] #[required] pub text: EcoString, diff --git a/library/src/math/root.rs b/library/src/math/root.rs index e190c65f..cb01e6a1 100644 --- a/library/src/math/root.rs +++ b/library/src/math/root.rs @@ -12,7 +12,6 @@ use super::*; #[node(LayoutMath)] pub struct SqrtNode { /// The expression to take the square root of. - #[positional] #[required] pub radicand: Content, } @@ -35,12 +34,10 @@ impl LayoutMath for SqrtNode { #[node(LayoutMath)] pub struct RootNode { /// Which root of the radicand to take. - #[positional] #[required] index: Content, /// The expression to take the root of. - #[positional] #[required] radicand: Content, } diff --git a/library/src/math/style.rs b/library/src/math/style.rs index 43c1f391..60bad6a5 100644 --- a/library/src/math/style.rs +++ b/library/src/math/style.rs @@ -12,7 +12,6 @@ use super::*; #[node(LayoutMath)] pub struct BoldNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -38,7 +37,6 @@ impl LayoutMath for BoldNode { #[node(LayoutMath)] pub struct UprightNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -61,7 +59,6 @@ impl LayoutMath for UprightNode { #[node(LayoutMath)] pub struct ItalicNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -84,7 +81,6 @@ impl LayoutMath for ItalicNode { #[node(LayoutMath)] pub struct SerifNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -110,7 +106,6 @@ impl LayoutMath for SerifNode { #[node(LayoutMath)] pub struct SansNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -136,7 +131,6 @@ impl LayoutMath for SansNode { #[node(LayoutMath)] pub struct CalNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -162,7 +156,6 @@ impl LayoutMath for CalNode { #[node(LayoutMath)] pub struct FrakNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -188,7 +181,6 @@ impl LayoutMath for FrakNode { #[node(LayoutMath)] pub struct MonoNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } @@ -219,7 +211,6 @@ impl LayoutMath for MonoNode { #[node(LayoutMath)] pub struct BbNode { /// The piece of formula to style. - #[positional] #[required] pub body: Content, } diff --git a/library/src/math/underover.rs b/library/src/math/underover.rs index 2aabf132..a723ae97 100644 --- a/library/src/math/underover.rs +++ b/library/src/math/underover.rs @@ -16,7 +16,6 @@ const BRACKET_GAP: Em = Em::new(0.25); #[node(LayoutMath)] pub struct UnderlineNode { /// The content above the line. - #[positional] #[required] pub body: Content, } @@ -39,7 +38,6 @@ impl LayoutMath for UnderlineNode { #[node(LayoutMath)] pub struct OverlineNode { /// The content below the line. - #[positional] #[required] pub body: Content, } @@ -62,7 +60,6 @@ impl LayoutMath for OverlineNode { #[node(LayoutMath)] pub struct UnderbraceNode { /// The content above the brace. - #[positional] #[required] pub body: Content, @@ -89,7 +86,6 @@ impl LayoutMath for UnderbraceNode { #[node(LayoutMath)] pub struct OverbraceNode { /// The content below the brace. - #[positional] #[required] pub body: Content, @@ -116,7 +112,6 @@ impl LayoutMath for OverbraceNode { #[node(LayoutMath)] pub struct UnderbracketNode { /// The content above the bracket. - #[positional] #[required] pub body: Content, @@ -143,7 +138,6 @@ impl LayoutMath for UnderbracketNode { #[node(LayoutMath)] pub struct OverbracketNode { /// The content below the bracket. - #[positional] #[required] pub body: Content, diff --git a/library/src/meta/heading.rs b/library/src/meta/heading.rs index 09cbc8b1..3a8d811c 100644 --- a/library/src/meta/heading.rs +++ b/library/src/meta/heading.rs @@ -74,7 +74,6 @@ pub struct HeadingNode { pub outlined: bool, /// The heading's title. - #[positional] #[required] pub body: Content, } diff --git a/library/src/meta/link.rs b/library/src/meta/link.rs index d4d4d8ca..572c55b4 100644 --- a/library/src/meta/link.rs +++ b/library/src/meta/link.rs @@ -46,7 +46,6 @@ pub struct LinkNode { /// ] /// ``` /// - #[positional] #[required] #[parse( let dest = args.expect::<Destination>("destination")?; @@ -59,7 +58,6 @@ pub struct LinkNode { /// The content that should become a link. If `dest` is an URL string, the /// parameter can be omitted. In this case, the URL will be shown as the /// link. - #[positional] #[required] #[parse(match &dest { Destination::Url(url) => match args.eat()? { diff --git a/library/src/meta/numbering.rs b/library/src/meta/numbering.rs index d3e1ee4d..4e6e1aed 100644 --- a/library/src/meta/numbering.rs +++ b/library/src/meta/numbering.rs @@ -27,46 +27,42 @@ use crate::text::Case; /// ) /// ``` /// -/// ## Parameters -/// - numbering: `Numbering` (positional, required) -/// Defines how the numbering works. -/// -/// **Counting symbols** are `1`, `a`, `A`, `i`, `I` and `*`. They are -/// replaced by the number in the sequence, in the given case. -/// -/// The `*` character means that symbols should be used to count, in the -/// order of `*`, `†`, `‡`, `§`, `¶`, and `‖`. If there are more than six -/// items, the number is represented using multiple symbols. -/// -/// **Suffixes** are all characters after the last counting symbol. They are -/// repeated as-is at the end of any rendered number. -/// -/// **Prefixes** are all characters that are neither counting symbols nor -/// suffixes. They are repeated as-is at in front of their rendered -/// equivalent of their counting symbol. -/// -/// This parameter can also be an arbitrary function that gets each number as -/// an individual argument. When given a function, the `numbering` function -/// just forwards the arguments to that function. While this is not -/// particularly useful in itself, it means that you can just give arbitrary -/// numberings to the `numbering` function without caring whether they are -/// defined as a pattern or function. -/// -/// - numbers: `NonZeroUsize` (positional, variadic) -/// The numbers to apply the numbering to. Must be positive. -/// -/// If `numbering` is a pattern and more numbers than counting symbols are -/// given, the last counting symbol with its prefix is repeated. -/// -/// - returns: any -/// /// Display: Numbering /// Category: meta +/// Returns: any #[func] -pub fn numbering(vm: &Vm, args: &mut Args) -> SourceResult<Value> { - let numbering = args.expect::<Numbering>("pattern or function")?; - let numbers = args.all::<NonZeroUsize>()?; - numbering.apply(vm.world(), &numbers) +pub fn numbering( + /// Defines how the numbering works. + /// + /// **Counting symbols** are `1`, `a`, `A`, `i`, `I` and `*`. They are + /// replaced by the number in the sequence, in the given case. + /// + /// The `*` character means that symbols should be used to count, in the + /// order of `*`, `†`, `‡`, `§`, `¶`, and `‖`. If there are more than six + /// items, the number is represented using multiple symbols. + /// + /// **Suffixes** are all characters after the last counting symbol. They are + /// repeated as-is at the end of any rendered number. + /// + /// **Prefixes** are all characters that are neither counting symbols nor + /// suffixes. They are repeated as-is at in front of their rendered + /// equivalent of their counting symbol. + /// + /// This parameter can also be an arbitrary function that gets each number as + /// an individual argument. When given a function, the `numbering` function + /// just forwards the arguments to that function. While this is not + /// particularly useful in itself, it means that you can just give arbitrary + /// numberings to the `numbering` function without caring whether they are + /// defined as a pattern or function. + numbering: Numbering, + /// The numbers to apply the numbering to. Must be positive. + /// + /// If `numbering` is a pattern and more numbers than counting symbols are + /// given, the last counting symbol with its prefix is repeated. + #[variadic] + numbers: Vec<NonZeroUsize>, +) -> Value { + numbering.apply(vm.world(), &numbers)? } /// How to number an enumeration. diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs index 55051b5e..20354556 100644 --- a/library/src/meta/reference.rs +++ b/library/src/meta/reference.rs @@ -20,7 +20,6 @@ use crate::text::TextNode; #[node(Show)] pub struct RefNode { /// The label that should be referenced. - #[positional] #[required] pub target: EcoString, } diff --git a/library/src/text/deco.rs b/library/src/text/deco.rs index 2a552226..4dadf45a 100644 --- a/library/src/text/deco.rs +++ b/library/src/text/deco.rs @@ -61,7 +61,6 @@ pub struct UnderlineNode { pub evade: bool, /// The content to underline. - #[positional] #[required] pub body: Content, } @@ -141,7 +140,6 @@ pub struct OverlineNode { pub evade: bool, /// The content to add a line over. - #[positional] #[required] pub body: Content, } @@ -206,7 +204,6 @@ pub struct StrikeNode { pub extent: Length, /// The content to strike through. - #[positional] #[required] pub body: Content, } diff --git a/library/src/text/misc.rs b/library/src/text/misc.rs index 64ab5bd2..60521f12 100644 --- a/library/src/text/misc.rs +++ b/library/src/text/misc.rs @@ -94,7 +94,6 @@ pub struct StrongNode { pub delta: i64, /// The content to strongly emphasize. - #[positional] #[required] pub body: Content, } @@ -155,7 +154,6 @@ impl Fold for Delta { #[node(Show)] pub struct EmphNode { /// The content to emphasize. - #[positional] #[required] pub body: Content, } @@ -196,15 +194,15 @@ impl Fold for Toggle { /// #lower[already low] /// ``` /// -/// ## Parameters -/// - text: `ToCase` (positional, required) -/// The text to convert to lowercase. -/// /// Display: Lowercase /// Category: text +/// Returns: string or content #[func] -pub fn lower(args: &mut Args) -> SourceResult<Value> { - case(Case::Lower, args) +pub fn lower( + /// The text to convert to lowercase. + text: ToCase, +) -> Value { + case(text, Case::Lower) } /// Convert text or content to uppercase. @@ -216,23 +214,23 @@ pub fn lower(args: &mut Args) -> SourceResult<Value> { /// #upper[ALREADY HIGH] /// ``` /// -/// ## Parameters -/// - text: `ToCase` (positional, required) -/// The text to convert to uppercase. -/// /// Display: Uppercase /// Category: text +/// Returns: string or content #[func] -pub fn upper(args: &mut Args) -> SourceResult<Value> { - case(Case::Upper, args) +pub fn upper( + /// The text to convert to uppercase. + text: ToCase, +) -> Value { + case(text, Case::Upper) } /// Change the case of text. -fn case(case: Case, args: &mut Args) -> SourceResult<Value> { - Ok(match args.expect("string or content")? { +fn case(text: ToCase, case: Case) -> Value { + match text { ToCase::Str(v) => Value::Str(case.apply(&v).into()), ToCase::Content(v) => Value::Content(v.styled(TextNode::set_case(Some(case)))), - }) + } } /// A value whose case can be changed. @@ -302,16 +300,15 @@ cast_to_value! { /// #lorem(40) /// ``` /// -/// ## Parameters -/// - text: `Content` (positional, required) -/// The text to display to small capitals. -/// /// Display: Small Capitals /// Category: text +/// Returns: content #[func] -pub fn smallcaps(args: &mut Args) -> SourceResult<Value> { - let body: Content = args.expect("content")?; - Ok(Value::Content(body.styled(TextNode::set_smallcaps(true)))) +pub fn smallcaps( + /// The text to display to small capitals. + body: Content, +) -> Value { + Value::Content(body.styled(TextNode::set_smallcaps(true))) } /// Create blind text. @@ -330,16 +327,13 @@ pub fn smallcaps(args: &mut Args) -> SourceResult<Value> { /// #lorem(15) /// ``` /// -/// ## Parameters -/// - words: `usize` (positional, required) -/// The length of the blind text in words. -/// -/// - returns: string -/// /// Display: Blind Text /// Category: text +/// Returns: string #[func] -pub fn lorem(args: &mut Args) -> SourceResult<Value> { - let words: usize = args.expect("number of words")?; - Ok(Value::Str(lipsum::lipsum(words).replace("--", "–").into())) +pub fn lorem( + /// The length of the blind text in words. + words: usize, +) -> Value { + Value::Str(lipsum::lipsum(words).replace("--", "–").into()) } diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs index 83f4e2d7..a81ef3d7 100644 --- a/library/src/text/mod.rs +++ b/library/src/text/mod.rs @@ -38,10 +38,6 @@ use crate::prelude::*; /// ]) /// ``` /// -/// ## Parameters -/// - body: `Content` (positional, required) -/// Content in which all text is styled according to the other arguments. -/// /// Display: Text /// Category: text #[node(Construct)] @@ -447,9 +443,13 @@ pub struct TextNode { #[fold] pub features: FontFeatures, + /// Content in which all text is styled according to the other arguments. + #[external] + #[required] + pub body: Content, + /// The text. #[internal] - #[positional] #[required] pub text: EcoString, diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs index 36a0fc78..3768e65e 100644 --- a/library/src/text/raw.rs +++ b/library/src/text/raw.rs @@ -57,7 +57,6 @@ pub struct RawNode { /// 1 + 2 + 3 + 4 + 5 /// ``` /// ```` - #[positional] #[required] pub text: EcoString, diff --git a/library/src/text/shift.rs b/library/src/text/shift.rs index ccdb0197..acd46d4e 100644 --- a/library/src/text/shift.rs +++ b/library/src/text/shift.rs @@ -42,7 +42,6 @@ pub struct SubNode { pub size: TextSize, /// The text to display in subscript. - #[positional] #[required] pub body: Content, } @@ -110,7 +109,6 @@ pub struct SuperNode { pub size: TextSize, /// The text to display in superscript. - #[positional] #[required] pub body: Content, } diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs index 1fdb418b..78f477f6 100644 --- a/library/src/visualize/image.rs +++ b/library/src/visualize/image.rs @@ -23,7 +23,6 @@ use crate::prelude::*; #[node(Layout)] pub struct ImageNode { /// Path to an image file. - #[positional] #[required] #[parse( let Spanned { v: path, span } = diff --git a/library/src/visualize/line.rs b/library/src/visualize/line.rs index 015abbb0..b39170f0 100644 --- a/library/src/visualize/line.rs +++ b/library/src/visualize/line.rs @@ -21,15 +21,15 @@ pub struct LineNode { /// The offset from `start` where the line ends. #[resolve] - pub end: Smart<Axes<Rel<Length>>>, + pub end: Option<Axes<Rel<Length>>>, - /// The line's length. Mutually exclusive with `end`. + /// The line's length. This is only respected if `end` is `none`. #[resolve] #[default(Abs::pt(30.0).into())] pub length: Rel<Length>, - /// The angle at which the line points away from the origin. Mutually - /// exclusive with `end`. + /// The angle at which the line points away from the origin. This is only + /// respected if `end` is `none`. pub angle: Angle, /// How to stroke the line. This can be: diff --git a/library/src/visualize/shape.rs b/library/src/visualize/shape.rs index ab953846..02b45ed5 100644 --- a/library/src/visualize/shape.rs +++ b/library/src/visualize/shape.rs @@ -176,15 +176,15 @@ impl Layout for RectNode { /// ] /// ``` /// -/// ## Parameters -/// - size: `Smart<Length>` (named, settable) -/// The square's side length. This is mutually exclusive with `width` and -/// `height`. -/// /// Display: Square /// Category: visualize #[node(Layout)] pub struct SquareNode { + /// The square's side length. This is mutually exclusive with `width` and + /// `height`. + #[external] + pub size: Smart<Length>, + /// The square's width. This is mutually exclusive with `size` and `height`. /// /// In contrast to `size`, this can be relative to the parent container's @@ -367,15 +367,15 @@ impl Layout for EllipseNode { /// ] /// ``` /// -/// ## Parameters -/// - radius: `Length` (named, settable) -/// The circle's radius. This is mutually exclusive with `width` and -/// `height`. -/// /// Display: Circle /// Category: visualize #[node(Layout)] pub struct CircleNode { + /// The circle's radius. This is mutually exclusive with `width` and + /// `height`. + #[external] + pub radius: Length, + /// The circle's width. This is mutually exclusive with `radius` and /// `height`. /// |
