diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-12-15 22:51:55 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-12-15 23:11:20 +0100 |
| commit | b6202b646a0d5ecced301d9bac8bfcaf977d7ee4 (patch) | |
| tree | 7d42cb50f9e66153e7e8b2217009684e25f54f42 /library | |
| parent | f3980c704544a464f9729cc8bc9f97d3a7454769 (diff) | |
Reflection for castables
Diffstat (limited to 'library')
39 files changed, 323 insertions, 153 deletions
diff --git a/library/src/basics/heading.rs b/library/src/basics/heading.rs index 80f93e8d..60415697 100644 --- a/library/src/basics/heading.rs +++ b/library/src/basics/heading.rs @@ -6,6 +6,8 @@ use crate::prelude::*; use crate::text::{SpaceNode, TextNode, TextSize}; /// A section heading. +/// +/// Tags: basics. #[func] #[capable(Prepare, Show, Finalize)] #[derive(Debug, Hash)] diff --git a/library/src/basics/list.rs b/library/src/basics/list.rs index 0fa8f125..4c016128 100644 --- a/library/src/basics/list.rs +++ b/library/src/basics/list.rs @@ -4,6 +4,8 @@ use crate::prelude::*; use crate::text::{SpaceNode, TextNode}; /// An unordered (bulleted) or ordered (numbered) list. +/// +/// Tags: basics. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -24,7 +26,7 @@ pub type DescNode = ListNode<DESC>; impl<const L: ListKind> ListNode<L> { /// How the list is labelled. #[property(referenced)] - pub const LABEL: Label = Label::Default; + pub const LABEL: ListLabel = ListLabel::Default; /// The indentation of each item's label. #[property(resolve)] pub const INDENT: Length = Length::zero(); @@ -199,10 +201,10 @@ pub struct DescItem { castable! { DescItem, - Expected: "dictionary with `term` and `body` keys", - Value::Dict(dict) => { - let term: Content = dict.get("term")?.clone().cast()?; - let body: Content = dict.get("body")?.clone().cast()?; + mut dict: Dict => { + let term: Content = dict.take("term")?.cast()?; + let body: Content = dict.take("body")?.cast()?; + dict.finish(&["term", "body"])?; Self { term, body } }, } @@ -221,7 +223,7 @@ pub const DESC: ListKind = 2; /// How to label a list or enumeration. #[derive(Debug, Clone, Hash)] -pub enum Label { +pub enum ListLabel { /// The default labelling. Default, /// A pattern with prefix, numbering, lower / upper case and suffix. @@ -232,7 +234,7 @@ pub enum Label { Func(Func, Span), } -impl Label { +impl ListLabel { /// Resolve the label based on the level. pub fn resolve( &self, @@ -256,9 +258,12 @@ impl Label { } } -impl Cast<Spanned<Value>> for Label { +impl Cast<Spanned<Value>> for ListLabel { fn is(value: &Spanned<Value>) -> bool { - matches!(&value.v, Value::Content(_) | Value::Func(_)) + matches!( + &value.v, + Value::None | Value::Str(_) | Value::Content(_) | Value::Func(_) + ) } fn cast(value: Spanned<Value>) -> StrResult<Self> { @@ -267,10 +272,15 @@ impl Cast<Spanned<Value>> for Label { Value::Str(v) => Ok(Self::Pattern(v.parse()?)), Value::Content(v) => Ok(Self::Content(v)), Value::Func(v) => Ok(Self::Func(v, value.span)), - v => Err(format_eco!( - "expected string, content or function, found {}", - v.type_name(), - )), + v => Self::error(v), } } + + fn describe() -> CastInfo { + CastInfo::Union(vec![ + CastInfo::Type("string"), + CastInfo::Type("content"), + CastInfo::Type("function"), + ]) + } } diff --git a/library/src/basics/table.rs b/library/src/basics/table.rs index 5a4e8e81..10a9143f 100644 --- a/library/src/basics/table.rs +++ b/library/src/basics/table.rs @@ -2,6 +2,8 @@ use crate::layout::{GridNode, TrackSizing, TrackSizings}; use crate::prelude::*; /// A table of items. +/// +/// Tags: basics. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -125,9 +127,12 @@ impl<T: Cast> Cast<Spanned<Value>> for Celled<T> { fn cast(value: Spanned<Value>) -> StrResult<Self> { match value.v { Value::Func(v) => Ok(Self::Func(v, value.span)), - v => T::cast(v) - .map(Self::Value) - .map_err(|msg| with_alternative(msg, "function")), + v if T::is(&v) => Ok(Self::Value(T::cast(v)?)), + v => Self::error(v), } } + + fn describe() -> CastInfo { + T::describe() + CastInfo::Type("function") + } } diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs index 71e43e21..62d0a419 100644 --- a/library/src/compute/calc.rs +++ b/library/src/compute/calc.rs @@ -3,6 +3,8 @@ use std::cmp::Ordering; use crate::prelude::*; /// The absolute value of a numeric value. +/// +/// Tags: calculate. #[func] pub fn abs(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("numeric value")?; @@ -20,12 +22,16 @@ pub fn abs(args: &mut Args) -> SourceResult<Value> { } /// The minimum of a sequence of values. +/// +/// Tags: calculate. #[func] pub fn min(args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Less) } /// The maximum of a sequence of values. +/// +/// Tags: calculate. #[func] pub fn max(args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Greater) @@ -53,18 +59,24 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { } /// Whether an integer is even. +/// +/// Tags: calculate. #[func] pub fn even(args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0)) } /// Whether an integer is odd. +/// +/// Tags: calculate. #[func] pub fn odd(args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0)) } /// The modulo of two numbers. +/// +/// Tags: calculate. #[func] pub fn mod_(args: &mut Args) -> SourceResult<Value> { let Spanned { v: v1, span: span1 } = args.expect("integer or float")?; diff --git a/library/src/compute/create.rs b/library/src/compute/create.rs index acd2e31f..a0eecfb8 100644 --- a/library/src/compute/create.rs +++ b/library/src/compute/create.rs @@ -5,6 +5,8 @@ use typst::model::Regex; use crate::prelude::*; /// Convert a value to an integer. +/// +/// Tags: create. #[func] pub fn int(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; @@ -21,6 +23,8 @@ pub fn int(args: &mut Args) -> SourceResult<Value> { } /// Convert a value to a float. +/// +/// Tags: create. #[func] pub fn float(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; @@ -36,6 +40,8 @@ pub fn float(args: &mut Args) -> SourceResult<Value> { } /// Create a grayscale color. +/// +/// Tags: create. #[func] pub fn luma(args: &mut Args) -> SourceResult<Value> { let Component(luma) = args.expect("gray component")?; @@ -43,6 +49,8 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> { } /// Create an RGB(A) color. +/// +/// Tags: create. #[func] pub fn rgb(args: &mut Args) -> SourceResult<Value> { Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? { @@ -60,6 +68,8 @@ pub fn rgb(args: &mut Args) -> SourceResult<Value> { } /// Create a CMYK color. +/// +/// Tags: create. #[func] pub fn cmyk(args: &mut Args) -> SourceResult<Value> { let RatioComponent(c) = args.expect("cyan component")?; @@ -74,12 +84,11 @@ struct Component(u8); castable! { Component, - Expected: "integer or ratio", - Value::Int(v) => match v { + v: i64 => match v { 0 ..= 255 => Self(v as u8), _ => Err("must be between 0 and 255")?, }, - Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { + v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { Err("must be between 0% and 100%")? @@ -91,8 +100,7 @@ struct RatioComponent(u8); castable! { RatioComponent, - Expected: "ratio", - Value::Ratio(v) => if (0.0 ..= 1.0).contains(&v.get()) { + v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { Err("must be between 0% and 100%")? @@ -100,6 +108,8 @@ castable! { } /// Convert a value to a string. +/// +/// Tags: create. #[func] pub fn str(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; @@ -113,12 +123,16 @@ pub fn str(args: &mut Args) -> SourceResult<Value> { } /// Create a label from a string. +/// +/// Tags: create. #[func] pub fn label(args: &mut Args) -> SourceResult<Value> { Ok(Value::Label(Label(args.expect("string")?))) } /// Create a regular expression from a string. +/// +/// Tags: create. #[func] pub fn regex(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?; @@ -126,6 +140,8 @@ pub fn regex(args: &mut Args) -> SourceResult<Value> { } /// Create an array consisting of a sequence of numbers. +/// +/// Tags: create. #[func] pub fn range(args: &mut Args) -> SourceResult<Value> { let first = args.expect::<i64>("end")?; diff --git a/library/src/compute/data.rs b/library/src/compute/data.rs index 57dce5c1..af545304 100644 --- a/library/src/compute/data.rs +++ b/library/src/compute/data.rs @@ -5,6 +5,8 @@ use typst::diag::{format_xml_like_error, FileError}; use crate::prelude::*; /// Read structured data from a CSV file. +/// +/// Tags: data-loading. #[func] pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = @@ -46,6 +48,8 @@ fn format_csv_error(error: csv::Error) -> String { } /// Read structured data from a JSON file. +/// +/// Tags: data-loading. #[func] pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = @@ -87,6 +91,8 @@ fn format_json_error(error: serde_json::Error) -> String { } /// Read structured data from an XML file. +/// +/// Tags: data-loading. #[func] pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = diff --git a/library/src/compute/foundations.rs b/library/src/compute/foundations.rs index abe797dc..22d26553 100644 --- a/library/src/compute/foundations.rs +++ b/library/src/compute/foundations.rs @@ -5,18 +5,24 @@ use typst::model; use typst::syntax::Source; /// The name of a value's type. +/// +/// Tags: foundations. #[func] pub fn type_(args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.type_name().into()) } /// The string representation of a value. +/// +/// Tags: foundations. #[func] pub fn repr(args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.repr().into()) } /// Ensure that a condition is fulfilled. +/// +/// Tags: foundations. #[func] pub fn assert(args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?; @@ -27,6 +33,8 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> { } /// Evaluate a string as Typst markup. +/// +/// Tags: foundations. #[func] pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; diff --git a/library/src/compute/utility.rs b/library/src/compute/utility.rs index d48f794e..5a6534f4 100644 --- a/library/src/compute/utility.rs +++ b/library/src/compute/utility.rs @@ -4,6 +4,8 @@ use crate::prelude::*; use crate::text::Case; /// Create a blind text string. +/// +/// Tags: utility. #[func] pub fn lorem(args: &mut Args) -> SourceResult<Value> { let words: usize = args.expect("number of words")?; @@ -11,6 +13,8 @@ pub fn lorem(args: &mut Args) -> SourceResult<Value> { } /// Apply a numbering pattern to a number. +/// +/// Tags: utility. #[func] pub fn numbering(args: &mut Args) -> SourceResult<Value> { let pattern = args.expect::<NumberingPattern>("pattern")?; @@ -93,8 +97,7 @@ impl FromStr for NumberingPattern { castable! { NumberingPattern, - Expected: "numbering pattern", - Value::Str(s) => s.parse()?, + string: EcoString => string.parse()?, } /// Different kinds of numberings. diff --git a/library/src/layout/align.rs b/library/src/layout/align.rs index 4fae3c3c..f00aeaf2 100644 --- a/library/src/layout/align.rs +++ b/library/src/layout/align.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Align content horizontally and vertically. +/// +/// Tags: layout. #[func] #[capable] #[derive(Debug, Hash)] diff --git a/library/src/layout/columns.rs b/library/src/layout/columns.rs index 0e29bc00..3bbf56e4 100644 --- a/library/src/layout/columns.rs +++ b/library/src/layout/columns.rs @@ -2,6 +2,8 @@ use crate::prelude::*; use crate::text::TextNode; /// Separate a region into multiple equally sized columns. +/// +/// Tags: layout. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -103,6 +105,8 @@ impl Layout for ColumnsNode { } /// A column break. +/// +/// Tags: layout. #[func] #[capable(Behave)] #[derive(Debug, Hash)] diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs index 85257715..d451bccf 100644 --- a/library/src/layout/container.rs +++ b/library/src/layout/container.rs @@ -2,6 +2,8 @@ use super::VNode; use crate::prelude::*; /// An inline-level container that sizes content. +/// +/// Tags: layout. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] @@ -62,6 +64,8 @@ impl Layout for BoxNode { impl Inline for BoxNode {} /// A block-level container that places content into a separate flow. +/// +/// Tags: layout. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -70,10 +74,10 @@ pub struct BlockNode(pub Content); #[node] impl BlockNode { /// The spacing between the previous and this block. - #[property(skip)] + #[property(reflect, skip)] pub const ABOVE: VNode = VNode::block_spacing(Em::new(1.2).into()); /// The spacing between this and the following block. - #[property(skip)] + #[property(reflect, skip)] pub const BELOW: VNode = VNode::block_spacing(Em::new(1.2).into()); /// Whether this block must stick to the following one. #[property(skip)] diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs index 2a6bd4ff..e70210c0 100644 --- a/library/src/layout/grid.rs +++ b/library/src/layout/grid.rs @@ -3,6 +3,8 @@ use crate::prelude::*; use super::Spacing; /// Arrange content in a grid. +/// +/// Tags: layout. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -85,17 +87,9 @@ pub struct TrackSizings(pub Vec<TrackSizing>); castable! { TrackSizings, - Expected: "integer, auto, relative length, fraction, or array of the latter three", - Value::Auto => Self(vec![TrackSizing::Auto]), - Value::Length(v) => Self(vec![TrackSizing::Relative(v.into())]), - Value::Ratio(v) => Self(vec![TrackSizing::Relative(v.into())]), - Value::Relative(v) => Self(vec![TrackSizing::Relative(v)]), - Value::Fraction(v) => Self(vec![TrackSizing::Fractional(v)]), - Value::Int(v) => Self(vec![ - TrackSizing::Auto; - Value::Int(v).cast::<NonZeroUsize>()?.get() - ]), - Value::Array(values) => Self(values + sizing: TrackSizing => Self(vec![sizing]), + count: NonZeroUsize => Self(vec![TrackSizing::Auto; count.get()]), + values: Array => Self(values .into_iter() .filter_map(|v| v.cast().ok()) .collect()), @@ -103,12 +97,9 @@ castable! { castable! { TrackSizing, - Expected: "auto, relative length, or fraction", - Value::Auto => Self::Auto, - Value::Length(v) => Self::Relative(v.into()), - Value::Ratio(v) => Self::Relative(v.into()), - Value::Relative(v) => Self::Relative(v), - Value::Fraction(v) => Self::Fractional(v), + _: AutoValue => Self::Auto, + v: Rel<Length> => Self::Relative(v), + v: Fr => Self::Fractional(v), } /// Performs grid layout. diff --git a/library/src/layout/hide.rs b/library/src/layout/hide.rs index 1318b7ed..4e70dca9 100644 --- a/library/src/layout/hide.rs +++ b/library/src/layout/hide.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Hide content without affecting layout. +/// +/// Tags: layout. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] diff --git a/library/src/layout/pad.rs b/library/src/layout/pad.rs index 9c44919d..9d882ba4 100644 --- a/library/src/layout/pad.rs +++ b/library/src/layout/pad.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Pad content at the sides. +/// +/// Tags: layout. #[func] #[capable(Layout)] #[derive(Debug, Hash)] diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs index 5a23b27b..fe83137e 100644 --- a/library/src/layout/page.rs +++ b/library/src/layout/page.rs @@ -5,6 +5,8 @@ use crate::prelude::*; use crate::text::TextNode; /// Layouts its child onto one or multiple pages. +/// +/// Tags: layout. #[func] #[capable] #[derive(Clone, Hash)] @@ -12,6 +14,9 @@ pub struct PageNode(pub Content); #[node] impl PageNode { + /// The paper size. + #[property(reflect, skip, shorthand)] + pub const PAPER: Paper = Paper::A4; /// The unflipped width of the page. #[property(resolve)] pub const WIDTH: Smart<Length> = Smart::Custom(Paper::A4.width().into()); @@ -145,6 +150,8 @@ impl Debug for PageNode { } /// A page break. +/// +/// Tags: layout. #[func] #[capable] #[derive(Debug, Copy, Clone, Hash)] @@ -187,7 +194,10 @@ impl Marginal { impl Cast<Spanned<Value>> for Marginal { fn is(value: &Spanned<Value>) -> bool { - matches!(&value.v, Value::Content(_) | Value::Func(_)) + matches!( + &value.v, + Value::None | Value::Str(_) | Value::Content(_) | Value::Func(_) + ) } fn cast(value: Spanned<Value>) -> StrResult<Self> { @@ -196,43 +206,51 @@ impl Cast<Spanned<Value>> for Marginal { Value::Str(v) => Ok(Self::Content(TextNode::packed(v))), Value::Content(v) => Ok(Self::Content(v)), Value::Func(v) => Ok(Self::Func(v, value.span)), - v => Err(format_eco!( - "expected none, content or function, found {}", - v.type_name(), - )), + v => Self::error(v), } } + + fn describe() -> CastInfo { + CastInfo::Union(vec![ + CastInfo::Type("none"), + CastInfo::Type("content"), + CastInfo::Type("function"), + ]) + } } /// Specification of a paper. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Hash)] pub struct Paper { /// The width of the paper in millimeters. - width: f64, + width: Scalar, /// The height of the paper in millimeters. - height: f64, + height: Scalar, } impl Paper { /// The width of the paper. pub fn width(self) -> Abs { - Abs::mm(self.width) + Abs::mm(self.width.0) } /// The height of the paper. pub fn height(self) -> Abs { - Abs::mm(self.height) + Abs::mm(self.height.0) } } /// Defines paper constants and a paper parsing implementation. macro_rules! papers { - ($(($var:ident: $width:expr, $height: expr, $($pats:tt)*))*) => { + ($(($var:ident: $width:expr, $height: expr, $pat:literal))*) => { /// Predefined papers. /// /// Each paper is parsable from its name in kebab-case. impl Paper { - $(pub const $var: Self = Self { width: $width, height: $height };)* + $(pub const $var: Self = Self { + width: Scalar($width), + height: Scalar($height), + };)* } impl FromStr for Paper { @@ -240,18 +258,17 @@ macro_rules! papers { fn from_str(name: &str) -> Result<Self, Self::Err> { match name.to_lowercase().as_str() { - $($($pats)* => Ok(Self::$var),)* + $($pat => Ok(Self::$var),)* _ => Err("invalid paper name"), } } } - }; -} -castable! { - Paper, - Expected: "string", - Value::Str(string) => Self::from_str(&string)?, + castable! { + Paper, + $($pat => Self::$var,)* + } + }; } // All paper sizes in mm. diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index 925eea54..eed0dbb1 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -12,6 +12,8 @@ use crate::text::{ }; /// Arrange text, spacing and inline-level nodes into a paragraph. +/// +/// Tags: layout. #[func] #[capable] #[derive(Hash)] @@ -109,9 +111,8 @@ pub struct HorizontalAlign(pub GenAlign); castable! { HorizontalAlign, - Expected: "alignment", - @align: GenAlign => match align.axis() { - Axis::X => Self(*align), + align: GenAlign => match align.axis() { + Axis::X => Self(align), Axis::Y => Err("must be horizontal")?, }, } @@ -135,15 +136,15 @@ pub enum Linebreaks { castable! { Linebreaks, - Expected: "string", - Value::Str(string) => match string.as_str() { - "simple" => Self::Simple, - "optimized" => Self::Optimized, - _ => Err(r#"expected "simple" or "optimized""#)?, - }, + /// Determine the linebreaks in a simple first-fit style. + "simple" => Self::Simple, + /// Optimize the linebreaks for the whole paragraph. + "optimized" => Self::Optimized, } /// A paragraph break. +/// +/// Tags: layout. #[func] #[capable(Unlabellable)] #[derive(Debug, Hash)] diff --git a/library/src/layout/place.rs b/library/src/layout/place.rs index 4c9c0a46..c3fcd0d5 100644 --- a/library/src/layout/place.rs +++ b/library/src/layout/place.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Place content at an absolute position. +/// +/// Tags: layout. #[func] #[capable(Layout, Behave)] #[derive(Debug, Hash)] diff --git a/library/src/layout/repeat.rs b/library/src/layout/repeat.rs index 196f19de..a47dbb3e 100644 --- a/library/src/layout/repeat.rs +++ b/library/src/layout/repeat.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Repeats content to fill a line. +/// +/// Tags: layout. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] diff --git a/library/src/layout/spacing.rs b/library/src/layout/spacing.rs index 91e45b03..e961c0cf 100644 --- a/library/src/layout/spacing.rs +++ b/library/src/layout/spacing.rs @@ -3,6 +3,8 @@ use std::cmp::Ordering; use crate::prelude::*; /// Horizontal spacing. +/// +/// Tags: layout. #[func] #[capable(Behave)] #[derive(Debug, Copy, Clone, Hash)] @@ -52,6 +54,8 @@ impl Behave for HNode { } /// Vertical spacing. +/// +/// Tags: layout. #[func] #[capable(Behave)] #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd)] @@ -119,6 +123,11 @@ impl Behave for VNode { } } +castable! { + VNode, + spacing: Spacing => VNode::block_around(spacing), +} + /// Kinds of spacing. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Spacing { @@ -160,9 +169,6 @@ impl PartialOrd for Spacing { castable! { Spacing, - Expected: "relative length or fraction", - Value::Length(v) => Self::Relative(v.into()), - Value::Ratio(v) => Self::Relative(v.into()), - Value::Relative(v) => Self::Relative(v), - Value::Fraction(v) => Self::Fractional(v), + v: Rel<Length> => Self::Relative(v), + v: Fr => Self::Fractional(v), } diff --git a/library/src/layout/stack.rs b/library/src/layout/stack.rs index 1e956669..111e3433 100644 --- a/library/src/layout/stack.rs +++ b/library/src/layout/stack.rs @@ -4,6 +4,8 @@ use super::{AlignNode, Spacing}; use crate::prelude::*; /// Arrange content and spacing along an axis. +/// +/// Tags: layout. #[func] #[capable(Layout)] #[derive(Debug, Hash)] @@ -81,12 +83,8 @@ impl Debug for StackChild { castable! { StackChild, - Expected: "relative length, fraction, or content", - Value::Length(v) => Self::Spacing(Spacing::Relative(v.into())), - Value::Ratio(v) => Self::Spacing(Spacing::Relative(v.into())), - Value::Relative(v) => Self::Spacing(Spacing::Relative(v)), - Value::Fraction(v) => Self::Spacing(Spacing::Fractional(v)), - Value::Content(v) => Self::Block(v), + spacing: Spacing => Self::Spacing(spacing), + content: Content => Self::Block(content), } /// Performs stack layout. diff --git a/library/src/layout/transform.rs b/library/src/layout/transform.rs index 35b6709a..f1a89d4c 100644 --- a/library/src/layout/transform.rs +++ b/library/src/layout/transform.rs @@ -3,6 +3,8 @@ use typst::geom::Transform; use crate::prelude::*; /// Move content without affecting layout. +/// +/// Tags: layout. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] @@ -46,6 +48,8 @@ impl Layout for MoveNode { impl Inline for MoveNode {} /// Transform content without affecting layout. +/// +/// Tags: layout. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] diff --git a/library/src/math/matrix.rs b/library/src/math/matrix.rs index 2d32f4b5..21294b71 100644 --- a/library/src/math/matrix.rs +++ b/library/src/math/matrix.rs @@ -1,6 +1,8 @@ use super::*; /// A column vector. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -52,17 +54,19 @@ pub enum Delimiter { castable! { Delimiter, - Expected: "type of bracket or bar", - Value::Str(s) => match s.as_str() { - "(" => Self::Paren, - "[" => Self::Bracket, - "{" => Self::Brace, - "|" => Self::Bar, - _ => Err("expected \"(\", \"[\", \"{\", or \"|\"")?, - }, + /// Delimit matrices with parentheses. + "(" => Self::Paren, + /// Delimit matrices with brackets. + "[" => Self::Bracket, + /// Delimit matrices with curly braces. + "{" => Self::Brace, + /// Delimit matrices with vertical bars. + "|" => Self::Bar, } /// A case distinction. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 59c621e8..41cdb9f5 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -15,6 +15,8 @@ use crate::prelude::*; use crate::text::{FontFamily, LinebreakNode, SpaceNode, SymbolNode, TextNode}; /// A piece of a mathematical formula. +/// +/// Tags: math. #[func] #[capable(Show, Layout, Inline, Texify)] #[derive(Debug, Clone, Hash)] @@ -244,6 +246,8 @@ impl Texify for Content { } /// An atom in a math formula: `x`, `+`, `12`. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -283,6 +287,8 @@ impl Texify for AtomNode { } /// An accented node. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -358,6 +364,8 @@ impl Texify for AccNode { } /// A fraction. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -389,6 +397,8 @@ impl Texify for FracNode { } /// A binomial. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -420,6 +430,8 @@ impl Texify for BinomNode { } /// A sub- and/or superscript. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -456,6 +468,8 @@ impl Texify for ScriptNode { } /// A math alignment point: `&`, `&&`. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -471,6 +485,8 @@ impl Texify for AlignPointNode { } /// A square root. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -493,6 +509,8 @@ impl Texify for SqrtNode { } /// A floored expression. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -515,6 +533,8 @@ impl Texify for FloorNode { } /// A ceiled expression. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] diff --git a/library/src/math/style.rs b/library/src/math/style.rs index 0fdff740..444b1fb4 100644 --- a/library/src/math/style.rs +++ b/library/src/math/style.rs @@ -1,6 +1,8 @@ use super::*; /// Serif (roman) font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -23,6 +25,8 @@ impl Texify for SerifNode { } /// Sans-serif font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -45,6 +49,8 @@ impl Texify for SansNode { } /// Bold font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -67,6 +73,8 @@ impl Texify for BoldNode { } /// Italic font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -89,6 +97,8 @@ impl Texify for ItalNode { } /// Calligraphic font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -111,6 +121,8 @@ impl Texify for CalNode { } /// Fraktur font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -133,6 +145,8 @@ impl Texify for FrakNode { } /// Monospace font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] @@ -155,6 +169,8 @@ impl Texify for MonoNode { } /// Blackboard bold (double-struck) font style. +/// +/// Tags: math. #[func] #[capable(Texify)] #[derive(Debug, Hash)] diff --git a/library/src/meta/document.rs b/library/src/meta/document.rs index 1dae4a2a..8c664df3 100644 --- a/library/src/meta/document.rs +++ b/library/src/meta/document.rs @@ -2,6 +2,8 @@ use crate::layout::{LayoutRoot, PageNode}; use crate::prelude::*; /// The root node that represents a full document. +/// +/// Tags: meta. #[func] #[capable(LayoutRoot)] #[derive(Hash)] diff --git a/library/src/meta/link.rs b/library/src/meta/link.rs index 94328b00..6f5d8af1 100644 --- a/library/src/meta/link.rs +++ b/library/src/meta/link.rs @@ -2,6 +2,8 @@ use crate::prelude::*; use crate::text::TextNode; /// Link text and other elements to a destination. +/// +/// Tags: meta. #[func] #[capable(Show, Finalize)] #[derive(Debug, Hash)] diff --git a/library/src/meta/outline.rs b/library/src/meta/outline.rs index d0fbc3f7..27ca5944 100644 --- a/library/src/meta/outline.rs +++ b/library/src/meta/outline.rs @@ -4,6 +4,8 @@ use crate::prelude::*; use crate::text::{LinebreakNode, SpaceNode, TextNode}; /// A section outline (table of contents). +/// +/// Tags: meta. #[func] #[capable(Prepare, Show)] #[derive(Debug, Hash)] diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs index 657e5ef7..378d19d2 100644 --- a/library/src/meta/reference.rs +++ b/library/src/meta/reference.rs @@ -2,6 +2,8 @@ use crate::prelude::*; use crate::text::TextNode; /// A reference to a label. +/// +/// Tags: meta. #[func] #[capable(Show)] #[derive(Debug, Hash)] diff --git a/library/src/prelude.rs b/library/src/prelude.rs index 9b461389..36d49dbf 100644 --- a/library/src/prelude.rs +++ b/library/src/prelude.rs @@ -8,17 +8,17 @@ pub use std::num::NonZeroUsize; #[doc(no_inline)] pub use comemo::{Track, Tracked, TrackedMut}; #[doc(no_inline)] -pub use typst::diag::{bail, error, with_alternative, At, SourceResult, StrResult}; +pub use typst::diag::{bail, error, At, SourceResult, StrResult}; #[doc(no_inline)] pub use typst::doc::*; #[doc(no_inline)] pub use typst::geom::*; #[doc(no_inline)] pub use typst::model::{ - array, capability, capable, castable, dict, dynamic, format_str, func, node, Args, - Array, Cast, Content, Dict, Finalize, Fold, Func, Introspector, Label, Node, NodeId, - Prepare, Resolve, Selector, Show, Smart, StabilityProvider, Str, StyleChain, - StyleMap, StyleVec, Unlabellable, Value, Vm, Vt, + array, capability, capable, castable, dict, format_str, func, node, Args, Array, + AutoValue, Cast, CastInfo, Content, Dict, Finalize, Fold, Func, Introspector, Label, + Node, NodeId, NoneValue, Prepare, Resolve, Selector, Show, StabilityProvider, Str, + StyleChain, StyleMap, StyleVec, Unlabellable, Value, Vm, Vt, }; #[doc(no_inline)] pub use typst::syntax::{Span, Spanned}; diff --git a/library/src/text/deco.rs b/library/src/text/deco.rs index fceb4cfd..86866715 100644 --- a/library/src/text/deco.rs +++ b/library/src/text/deco.rs @@ -5,6 +5,8 @@ use super::TextNode; use crate::prelude::*; /// Typeset underline, stricken-through or overlined text. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] diff --git a/library/src/text/misc.rs b/library/src/text/misc.rs index 1c5a32b4..fc4f7d73 100644 --- a/library/src/text/misc.rs +++ b/library/src/text/misc.rs @@ -2,6 +2,8 @@ use super::TextNode; use crate::prelude::*; /// A text space. +/// +/// Tags: text. #[func] #[capable(Unlabellable, Behave)] #[derive(Debug, Hash)] @@ -23,6 +25,8 @@ impl Behave for SpaceNode { } /// A line break. +/// +/// Tags: text. #[func] #[capable(Behave)] #[derive(Debug, Hash)] @@ -45,6 +49,8 @@ impl Behave for LinebreakNode { } /// Strongly emphasizes content by increasing the font weight. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] @@ -79,8 +85,7 @@ pub struct Delta(pub i64); castable! { Delta, - Expected: "integer", - Value::Int(delta) => Self(delta), + v: i64 => Self(v), } impl Fold for Delta { @@ -92,6 +97,8 @@ impl Fold for Delta { } /// Emphasizes content by flipping the italicness. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] @@ -130,12 +137,16 @@ impl Fold for Toggle { } /// Convert a string or content to lowercase. +/// +/// Tags: text. #[func] pub fn lower(args: &mut Args) -> SourceResult<Value> { case(Case::Lower, args) } /// Convert a string or content to uppercase. +/// +/// Tags: text. #[func] pub fn upper(args: &mut Args) -> SourceResult<Value> { case(Case::Upper, args) @@ -171,6 +182,8 @@ impl Case { } /// Display text in small capitals. +/// +/// Tags: text. #[func] pub fn smallcaps(args: &mut Args) -> SourceResult<Value> { let body: Content = args.expect("content")?; diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs index d09d8f28..7340e5de 100644 --- a/library/src/text/mod.rs +++ b/library/src/text/mod.rs @@ -26,6 +26,8 @@ use crate::layout::ParNode; use crate::prelude::*; /// A single run of text with the same style. +/// +/// Tags: text. #[func] #[capable] #[derive(Clone, Hash)] @@ -206,8 +208,7 @@ impl Debug for FontFamily { castable! { FontFamily, - Expected: "string", - Value::Str(string) => Self::new(&string), + string: EcoString => Self::new(&string), } /// Font family fallback list. @@ -216,12 +217,10 @@ pub struct FallbackList(pub Vec<FontFamily>); castable! { FallbackList, - Expected: "string or array of strings", - Value::Str(string) => Self(vec![FontFamily::new(&string)]), - Value::Array(values) => Self(values + family: FontFamily => Self(vec![family]), + values: Array => Self(values .into_iter() .filter_map(|v| v.cast().ok()) - .map(|string: EcoString| FontFamily::new(&string)) .collect()), } @@ -237,7 +236,10 @@ impl Fold for TextSize { } } -castable!(TextSize: Length); +castable! { + TextSize, + v: Length => Self(v), +} /// Specifies the bottom or top edge of text. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -260,16 +262,17 @@ impl TextEdge { castable! { TextEdge, - Expected: "string or length", - Value::Length(v) => Self::Length(v), - Value::Str(string) => Self::Metric(match string.as_str() { - "ascender" => VerticalFontMetric::Ascender, - "cap-height" => VerticalFontMetric::CapHeight, - "x-height" => VerticalFontMetric::XHeight, - "baseline" => VerticalFontMetric::Baseline, - "descender" => VerticalFontMetric::Descender, - _ => Err("unknown font metric")?, - }), + v: Length => Self::Length(v), + /// The distance from the baseline to the ascender. + "ascender" => Self::Metric(VerticalFontMetric::Ascender), + /// The approximate height of uppercase letters. + "cap-height" => Self::Metric(VerticalFontMetric::CapHeight), + /// The approximate height of non-ascending lowercase letters. + "x-height" => Self::Metric(VerticalFontMetric::XHeight), + /// The baseline on which the letters rest. + "baseline" => Self::Metric(VerticalFontMetric::Baseline), + /// The distance from the baseline to the descender. + "descender" => Self::Metric(VerticalFontMetric::Descender), } /// The direction of text and inline objects in their line. @@ -278,10 +281,9 @@ pub struct HorizontalDir(pub Smart<Dir>); castable! { HorizontalDir, - Expected: "direction or auto", - Value::Auto => Self(Smart::Auto), - @dir: Dir => match dir.axis() { - Axis::X => Self(Smart::Custom(*dir)), + _: AutoValue => Self(Smart::Auto), + dir: Dir => match dir.axis() { + Axis::X => Self(Smart::Custom(dir)), Axis::Y => Err("must be horizontal")?, }, } @@ -303,9 +305,8 @@ pub struct Hyphenate(pub Smart<bool>); castable! { Hyphenate, - Expected: "boolean or auto", - Value::Auto => Self(Smart::Auto), - Value::Bool(v) => Self(Smart::Custom(v)), + _: AutoValue => Self(Smart::Auto), + v: bool => Self(Smart::Custom(v)), } impl Resolve for Hyphenate { @@ -337,8 +338,7 @@ impl StylisticSet { castable! { StylisticSet, - Expected: "integer", - Value::Int(v) => match v { + v: i64 => match v { 1 ..= 20 => Self::new(v as u8), _ => Err("must be between 1 and 20")?, }, @@ -355,12 +355,10 @@ pub enum NumberType { castable! { NumberType, - Expected: "string", - Value::Str(string) => match string.as_str() { - "lining" => Self::Lining, - "old-style" => Self::OldStyle, - _ => Err(r#"expected "lining" or "old-style""#)?, - }, + /// Numbers that fit well with capital text. + "lining" => Self::Lining, + /// Numbers that fit well into a flow of upper- and lowercase text. + "old-style" => Self::OldStyle, } /// The width of numbers / figures. @@ -374,12 +372,10 @@ pub enum NumberWidth { castable! { NumberWidth, - Expected: "string", - Value::Str(string) => match string.as_str() { - "proportional" => Self::Proportional, - "tabular" => Self::Tabular, - _ => Err(r#"expected "proportional" or "tabular""#)?, - }, + /// Number widths are glyph specific. + "proportional" => Self::Proportional, + /// All numbers are of equal width / monospaced. + "tabular" => Self::Tabular, } /// OpenType font features settings. @@ -388,20 +384,21 @@ pub struct FontFeatures(pub Vec<(Tag, u32)>); castable! { FontFeatures, - Expected: "array of strings or dictionary mapping tags to integers", - Value::Array(values) => Self(values + values: Array => Self(values .into_iter() - .filter_map(|v| v.cast().ok()) - .map(|string: EcoString| (Tag::from_bytes_lossy(string.as_bytes()), 1)) - .collect()), - Value::Dict(values) => Self(values + .map(|v| { + let tag = v.cast::<EcoString>()?; + Ok((Tag::from_bytes_lossy(tag.as_bytes()), 1)) + }) + .collect::<StrResult<_>>()?), + values: Dict => Self(values .into_iter() - .filter_map(|(k, v)| { + .map(|(k, v)| { + let num = v.cast::<u32>()?; let tag = Tag::from_bytes_lossy(k.as_bytes()); - let num = v.cast::<i64>().ok()?.try_into().ok()?; - Some((tag, num)) + Ok((tag, num)) }) - .collect()), + .collect::<StrResult<_>>()?), } impl Fold for FontFeatures { diff --git a/library/src/text/quotes.rs b/library/src/text/quotes.rs index 0f678de3..ab6f166c 100644 --- a/library/src/text/quotes.rs +++ b/library/src/text/quotes.rs @@ -3,6 +3,8 @@ use typst::syntax::is_newline; use crate::prelude::*; /// A smart quote. +/// +/// Tags: text. #[func] #[capable] #[derive(Debug, Hash)] diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs index 4ad70654..125a5da1 100644 --- a/library/src/text/raw.rs +++ b/library/src/text/raw.rs @@ -7,6 +7,8 @@ use crate::layout::BlockNode; use crate::prelude::*; /// Raw text with optional syntax highlighting. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] diff --git a/library/src/text/shift.rs b/library/src/text/shift.rs index 65adc027..ad4a6cd9 100644 --- a/library/src/text/shift.rs +++ b/library/src/text/shift.rs @@ -10,6 +10,8 @@ use crate::prelude::*; /// typography possible, we first try to transform the text to superscript /// codepoints. If that fails, we fall back to rendering shrunk normal letters /// in a raised way. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] diff --git a/library/src/text/symbol.rs b/library/src/text/symbol.rs index fc746eb2..eece81ab 100644 --- a/library/src/text/symbol.rs +++ b/library/src/text/symbol.rs @@ -2,6 +2,8 @@ use crate::prelude::*; use crate::text::TextNode; /// A symbol identified by symmie notation. +/// +/// Tags: text. #[func] #[capable(Show)] #[derive(Debug, Hash)] diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs index b8b05aec..936ec3bf 100644 --- a/library/src/visualize/image.rs +++ b/library/src/visualize/image.rs @@ -5,6 +5,8 @@ use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat}; use crate::prelude::*; /// Show a raster or vector graphic. +/// +/// Tags: visualize. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] @@ -112,11 +114,10 @@ pub enum ImageFit { castable! { ImageFit, - Expected: "string", - Value::Str(string) => match string.as_str() { - "cover" => Self::Cover, - "contain" => Self::Contain, - "stretch" => Self::Stretch, - _ => Err(r#"expected "cover", "contain" or "stretch""#)?, - }, + /// The image should completely cover the area. + "cover" => Self::Cover, + /// The image should be fully contained in the area. + "contain" => Self::Contain, + /// The image should be stretched so that it exactly fills the area. + "stretch" => Self::Stretch, } diff --git a/library/src/visualize/line.rs b/library/src/visualize/line.rs index ed6a3d92..9c9b8b00 100644 --- a/library/src/visualize/line.rs +++ b/library/src/visualize/line.rs @@ -1,6 +1,8 @@ use crate::prelude::*; /// Display a line without affecting the layout. +/// +/// Tags: visualize. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] diff --git a/library/src/visualize/shape.rs b/library/src/visualize/shape.rs index 702fc6f8..a3443189 100644 --- a/library/src/visualize/shape.rs +++ b/library/src/visualize/shape.rs @@ -3,6 +3,8 @@ use std::f64::consts::SQRT_2; use crate::prelude::*; /// A sizable and fillable shape with optional content. +/// +/// Tags: visualize. #[func] #[capable(Layout, Inline)] #[derive(Debug, Hash)] @@ -25,7 +27,7 @@ impl<const S: ShapeKind> ShapeNode<S> { /// How to fill the shape. pub const FILL: Option<Paint> = None; /// How to stroke the shape. - #[property(skip, resolve, fold)] + #[property(reflect, skip, resolve, fold)] pub const STROKE: Smart<Sides<Option<PartialStroke>>> = Smart::Auto; /// How much to pad the shape's content. @@ -36,7 +38,7 @@ impl<const S: ShapeKind> ShapeNode<S> { pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero()); /// How much to round the shape's corners. - #[property(skip, resolve, fold)] + #[property(reflect, skip, resolve, fold)] pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero()); fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { |
