summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/src/main.rs2
-rw-r--r--library/src/basics/heading.rs35
-rw-r--r--library/src/basics/list.rs10
-rw-r--r--library/src/basics/table.rs5
-rw-r--r--library/src/compute/calc.rs1
-rw-r--r--library/src/compute/create.rs12
-rw-r--r--library/src/compute/utility.rs1
-rw-r--r--library/src/layout/align.rs1
-rw-r--r--library/src/layout/columns.rs1
-rw-r--r--library/src/layout/container.rs5
-rw-r--r--library/src/layout/grid.rs5
-rw-r--r--library/src/layout/pad.rs7
-rw-r--r--library/src/layout/page.rs1
-rw-r--r--library/src/layout/place.rs3
-rw-r--r--library/src/layout/spacing.rs2
-rw-r--r--library/src/layout/stack.rs2
-rw-r--r--library/src/layout/transform.rs5
-rw-r--r--library/src/math/mod.rs6
-rw-r--r--library/src/meta/link.rs1
-rw-r--r--library/src/text/mod.rs1
-rw-r--r--library/src/text/raw.rs1
-rw-r--r--library/src/visualize/line.rs3
-rw-r--r--library/src/visualize/shape.rs5
-rw-r--r--macros/src/func.rs67
-rw-r--r--macros/src/lib.rs23
-rw-r--r--macros/src/node.rs7
-rw-r--r--src/font/book.rs4
-rw-r--r--src/font/mod.rs6
-rw-r--r--src/model/func.rs6
-rw-r--r--src/model/library.rs2
-rw-r--r--tests/src/tests.rs6
31 files changed, 199 insertions, 37 deletions
diff --git a/cli/src/main.rs b/cli/src/main.rs
index 7b961183..39769968 100644
--- a/cli/src/main.rs
+++ b/cli/src/main.rs
@@ -664,7 +664,7 @@ impl FontSearcher {
let path = path.as_ref();
if let Ok(file) = File::open(path) {
if let Ok(mmap) = unsafe { Mmap::map(&file) } {
- for (i, info) in FontInfo::from_data(&mmap).enumerate() {
+ for (i, info) in FontInfo::iter(&mmap).enumerate() {
self.book.push(info);
self.fonts.push(FontSlot {
path: path.into(),
diff --git a/library/src/basics/heading.rs b/library/src/basics/heading.rs
index 2781034e..b7d8c72c 100644
--- a/library/src/basics/heading.rs
+++ b/library/src/basics/heading.rs
@@ -7,9 +7,23 @@ use crate::text::{SpaceNode, TextNode, TextSize};
/// A section heading.
///
+/// # Example
+/// ```
+/// #set heading(numbering: "I.")
+///
+/// = Introduction
+/// In recent years, ...
+/// ```
+///
+/// # Syntax
+/// Headings can be created by starting a line with one or multiple equals
+/// signs. The number of equals signs determines the heading's logical nesting
+/// depth.
+///
/// # Parameters
/// - body: Content (positional, required)
/// The heading's contents.
+///
/// - level: NonZeroUsize (named)
/// The logical nesting depth of the heading, starting from one.
///
@@ -29,10 +43,31 @@ pub struct HeadingNode {
#[node]
impl HeadingNode {
/// How to number the heading.
+ ///
+ /// # Example
+ /// ```
+ /// #set heading(numbering: "1.a.")
+ ///
+ /// = A section
+ /// == A subsection
+ /// === A sub-subsection
+ /// ```
#[property(referenced)]
pub const NUMBERING: Option<NumberingPattern> = None;
/// Whether the heading should appear in the outline.
+ ///
+ /// # Example
+ /// ```
+ /// #outline()
+ ///
+ /// #heading[Normal]
+ /// This is a normal heading.
+ ///
+ /// #heading(outlined: false)[Hidden]
+ /// This heading does not appear
+ /// in the outline.
+ /// ```
pub const OUTLINED: bool = true;
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
diff --git a/library/src/basics/list.rs b/library/src/basics/list.rs
index c9215a50..15b26169 100644
--- a/library/src/basics/list.rs
+++ b/library/src/basics/list.rs
@@ -8,12 +8,22 @@ use crate::text::{SpaceNode, TextNode};
/// # Parameters
/// - items: Content (positional, variadic)
/// The contents of the list items.
+///
/// - start: NonZeroUsize (named)
/// Which number to start the enumeration with.
+///
/// - tight: bool (named)
/// Makes the list more compact, if enabled. This looks better if the items
/// fit into a single line each.
///
+/// # Example
+/// ```
+/// #show columns.with(2)
+/// #list(tight: true)[Tight][List]
+/// #colbreak()
+/// #list(tight: false)[Wide][List]
+/// ```
+///
/// # Tags
/// - basics
#[func]
diff --git a/library/src/basics/table.rs b/library/src/basics/table.rs
index d7e2e08f..05f2ffff 100644
--- a/library/src/basics/table.rs
+++ b/library/src/basics/table.rs
@@ -6,14 +6,19 @@ use crate::prelude::*;
/// # Parameters
/// - cells: Content (positional, variadic)
/// The contents of the table cells.
+///
/// - rows: TrackSizings (named)
/// Defines the row sizes.
+///
/// - columns: TrackSizings (named)
/// Defines the column sizes.
+///
/// - gutter: TrackSizings (named)
/// Defines the gaps between rows & columns.
+///
/// - column-gutter: TrackSizings (named)
/// Defines the gaps between columns. Takes precedence over `gutter`.
+///
/// - row-gutter: TrackSizings (named)
/// Defines the gaps between rows. Takes precedence over `gutter`.
///
diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs
index eccc4531..1984d5ef 100644
--- a/library/src/compute/calc.rs
+++ b/library/src/compute/calc.rs
@@ -105,6 +105,7 @@ pub fn odd(args: &mut Args) -> SourceResult<Value> {
/// # Parameters
/// - dividend: ToMod (positional, required)
/// The dividend of the modulus.
+///
/// - divisor: ToMod (positional, required)
/// The divisor of the modulus.
///
diff --git a/library/src/compute/create.rs b/library/src/compute/create.rs
index e3733d60..cb693a1c 100644
--- a/library/src/compute/create.rs
+++ b/library/src/compute/create.rs
@@ -77,12 +77,21 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> {
///
/// If this string is given, the individual components should not be given.
///
+/// # Example
+/// ```
+/// #let color = rgb("#239dad")
+/// #text(16pt, color)[*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.
///
@@ -125,10 +134,13 @@ castable! {
/// # 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.
///
diff --git a/library/src/compute/utility.rs b/library/src/compute/utility.rs
index bdad9618..ffad740e 100644
--- a/library/src/compute/utility.rs
+++ b/library/src/compute/utility.rs
@@ -22,6 +22,7 @@ pub fn lorem(args: &mut Args) -> SourceResult<Value> {
/// # Parameters
/// - pattern: NumberingPattern (positional, required)
/// A string that defines how the numbering works.
+///
/// - numbers: NonZeroUsize (positional, variadic)
/// The numbers to apply the pattern to.
///
diff --git a/library/src/layout/align.rs b/library/src/layout/align.rs
index 7853d84d..5426f5e2 100644
--- a/library/src/layout/align.rs
+++ b/library/src/layout/align.rs
@@ -5,6 +5,7 @@ use crate::prelude::*;
/// # Parameters
/// - body: Content (positional, required)
/// The content to align.
+///
/// - alignment: Axes<Option<GenAlign>> (positional, settable)
/// The alignment along both axes.
///
diff --git a/library/src/layout/columns.rs b/library/src/layout/columns.rs
index b31b0a6d..6154cd14 100644
--- a/library/src/layout/columns.rs
+++ b/library/src/layout/columns.rs
@@ -6,6 +6,7 @@ use crate::text::TextNode;
/// # Parameters
/// - count: usize (positional, required)
/// The number of columns.
+///
/// - body: Content (positional, required)
/// The content that should be layouted into the columns.
///
diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs
index 4b58434b..5df6b2dc 100644
--- a/library/src/layout/container.rs
+++ b/library/src/layout/container.rs
@@ -7,8 +7,10 @@ use crate::prelude::*;
/// # Parameters
/// - body: Content (positional)
/// The contents of the box.
+///
/// - width: Rel<Length> (named)
/// The width of the box.
+///
/// - height: Rel<Length> (named)
/// The height of the box.
///
@@ -78,11 +80,14 @@ impl Inline for BoxNode {}
/// # Parameters
/// - body: Content (positional)
/// The contents of the block.
+///
/// - spacing: Spacing (named, settable)
/// The spacing around this block.
+///
/// - above: Spacing (named, settable)
/// The spacing between the previous and this block. Takes precedence over
/// `spacing`.
+///
/// - below: Spacing (named, settable)
/// The spacing between this block and the following one. Takes precedence
/// over `spacing`.
diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs
index 8aaffe08..1cf95001 100644
--- a/library/src/layout/grid.rs
+++ b/library/src/layout/grid.rs
@@ -7,14 +7,19 @@ use super::Spacing;
/// # Parameters
/// - cells: Content (positional, variadic)
/// The contents of the table cells.
+///
/// - rows: TrackSizings (named)
/// Defines the row sizes.
+///
/// - columns: TrackSizings (named)
/// Defines the column sizes.
+///
/// - gutter: TrackSizings (named)
/// Defines the gaps between rows & columns.
+///
/// - column-gutter: TrackSizings (named)
/// Defines the gaps between columns. Takes precedence over `gutter`.
+///
/// - row-gutter: TrackSizings (named)
/// Defines the gaps between rows. Takes precedence over `gutter`.
///
diff --git a/library/src/layout/pad.rs b/library/src/layout/pad.rs
index 94492f83..1326ae22 100644
--- a/library/src/layout/pad.rs
+++ b/library/src/layout/pad.rs
@@ -5,18 +5,25 @@ use crate::prelude::*;
/// # Parameters
/// - body: Content (positional, required)
/// The content to pad at the sides.
+///
/// - left: Rel<Length> (named)
/// The padding at the left side.
+///
/// - right: Rel<Length> (named)
/// The padding at the right side.
+///
/// - top: Rel<Length> (named)
/// The padding at the top side.
+///
/// - bottom: Rel<Length> (named)
/// The padding at the bottom side.
+///
/// - x: Rel<Length> (named)
/// The horizontal padding. Both `left` and `right` take precedence over this.
+///
/// - y: Rel<Length> (named)
/// The vertical padding. Both `top` and `bottom` take precedence over this.
+///
/// - rest: Rel<Length> (named)
/// The padding for all sides. All other parameters take precedence over this.
///
diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs
index 8782ed08..a2548c02 100644
--- a/library/src/layout/page.rs
+++ b/library/src/layout/page.rs
@@ -9,6 +9,7 @@ use crate::text::TextNode;
/// # Parameters
/// - body: Content (positional, required)
/// The contents of the page(s).
+///
/// - paper: Paper (positional, settable)
/// The paper size.
///
diff --git a/library/src/layout/place.rs b/library/src/layout/place.rs
index 890480a7..8baf69af 100644
--- a/library/src/layout/place.rs
+++ b/library/src/layout/place.rs
@@ -5,10 +5,13 @@ use crate::prelude::*;
/// # Parameters
/// - alignment: Axes<Option<GenAlign>> (positional)
/// Relative to which position in the parent container to place the content.
+///
/// - body: Content (positional, required)
/// The content to place.
+///
/// - dx: Rel<Length> (named)
/// The horizontal displacement of the placed content.
+///
/// - dy: Rel<Length> (named)
/// The vertical displacement of the placed content.
///
diff --git a/library/src/layout/spacing.rs b/library/src/layout/spacing.rs
index ef69c070..092d2c0a 100644
--- a/library/src/layout/spacing.rs
+++ b/library/src/layout/spacing.rs
@@ -7,6 +7,7 @@ use crate::prelude::*;
/// # Parameters
/// - amount: Spacing (positional, required)
/// How much spacing to insert.
+///
/// - weak: bool (named)
/// If true, the spacing collapses at the start or end of a paragraph.
/// Moreover, from multiple adjacent weak spacings all but the largest one
@@ -67,6 +68,7 @@ impl Behave for HNode {
/// # Parameters
/// - amount: Spacing (positional, required)
/// How much spacing to insert.
+///
/// - weak: bool (named)
/// If true, the spacing collapses at the start or end of a flow.
/// Moreover, from multiple adjacent weak spacings all but the largest one
diff --git a/library/src/layout/stack.rs b/library/src/layout/stack.rs
index deb565b6..2683175a 100644
--- a/library/src/layout/stack.rs
+++ b/library/src/layout/stack.rs
@@ -8,8 +8,10 @@ use crate::prelude::*;
/// # Parameters
/// - items: StackChild (positional, variadic)
/// The items to stack along an axis.
+///
/// - dir: Dir (named)
/// The direction along which the items are stacked.
+///
/// - spacing: Spacing (named)
/// Spacing to insert between items where no explicit spacing was provided.
///
diff --git a/library/src/layout/transform.rs b/library/src/layout/transform.rs
index 3af44ca0..b509607d 100644
--- a/library/src/layout/transform.rs
+++ b/library/src/layout/transform.rs
@@ -7,8 +7,10 @@ use crate::prelude::*;
/// # Parameters
/// - body: Content (positional, required)
/// The content to move.
+///
/// - dx: Rel<Length> (named)
/// The horizontal displacement of the content.
+///
/// - dy: Rel<Length> (named)
/// The vertical displacement of the content.
///
@@ -61,10 +63,13 @@ impl Inline for MoveNode {}
/// # Parameters
/// - body: Content (positional, required)
/// The content to transform.
+///
/// - angle: Angle (named)
/// The amount of rotation.
+///
/// - x: Ratio (named)
/// The horizontal scaling factor.
+///
/// - y: Ratio (named)
/// The vertical scaling factor.
///
diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs
index 3bd7b2e3..5342a954 100644
--- a/library/src/math/mod.rs
+++ b/library/src/math/mod.rs
@@ -19,6 +19,7 @@ use crate::text::{FontFamily, LinebreakNode, SpaceNode, SymbolNode, TextNode};
/// # Parameters
/// - items: Content (positional, variadic)
/// The individual parts of the formula.
+///
/// - block: bool (named)
/// Whether the formula is displayed as a separate block.
///
@@ -309,6 +310,7 @@ impl Texify for AtomNode {
/// # Parameters
/// - base: Content (positional, required)
/// The base to which the accent is applied.
+///
/// - accent: Content (positional, required)
/// The accent to apply to the base.
///
@@ -393,6 +395,7 @@ impl Texify for AccNode {
/// # Parameters
/// - num: Content (positional, required)
/// The fraction's numerator.
+///
/// - denom: Content (positional, required)
/// The fraction's denominator.
///
@@ -433,6 +436,7 @@ impl Texify for FracNode {
/// # Parameters
/// - upper: Content (positional, required)
/// The binomial's upper index.
+///
/// - lower: Content (positional, required)
/// The binomial's lower index.
///
@@ -473,8 +477,10 @@ impl Texify for BinomNode {
/// # Parameters
/// - base: Content (positional, required)
/// The base to which the applies the sub- and/or superscript.
+///
/// - sub: Content (named)
/// The subscript.
+///
/// - sup: Content (named)
/// The superscript.
///
diff --git a/library/src/meta/link.rs b/library/src/meta/link.rs
index 27294a8d..6a2f66df 100644
--- a/library/src/meta/link.rs
+++ b/library/src/meta/link.rs
@@ -6,6 +6,7 @@ use crate::text::TextNode;
/// # Parameters
/// - dest: Destination (positional, required)
/// The destination the link points to.
+///
/// - body: Content (positional)
/// How the link is represented. Defaults to the destination if it is a link.
///
diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs
index 21dea8af..315de95d 100644
--- a/library/src/text/mod.rs
+++ b/library/src/text/mod.rs
@@ -30,6 +30,7 @@ use crate::prelude::*;
/// # Parameters
/// - family: EcoString (positional, variadic, settable)
/// A prioritized sequence of font families.
+///
/// - body: Content (positional, required)
/// Content in which all text is styled according to the other arguments.
///
diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs
index 74626588..55c29298 100644
--- a/library/src/text/raw.rs
+++ b/library/src/text/raw.rs
@@ -11,6 +11,7 @@ use crate::prelude::*;
/// # Parameters
/// - text: EcoString (positional, required)
/// The raw text.
+///
/// - block: bool (named)
/// Whether the raw text is displayed as a separate block.
///
diff --git a/library/src/visualize/line.rs b/library/src/visualize/line.rs
index 5c8c9644..6c60ef4e 100644
--- a/library/src/visualize/line.rs
+++ b/library/src/visualize/line.rs
@@ -7,10 +7,13 @@ use crate::prelude::*;
/// # Parameters
/// - origin: Axes<Rel<Length>> (named)
/// The start point of the line.
+///
/// - to: Axes<Rel<Length>> (named)
/// The end point of the line.
+///
/// - length: Rel<Length> (named)
/// The line's length.
+///
/// - angle: Angle (named)
/// The angle at which the line points away from the origin.
///
diff --git a/library/src/visualize/shape.rs b/library/src/visualize/shape.rs
index be80b4fb..9c66e867 100644
--- a/library/src/visualize/shape.rs
+++ b/library/src/visualize/shape.rs
@@ -7,14 +7,19 @@ use crate::prelude::*;
/// # Parameters
/// - body: Content (positional)
/// The content to place into the shape.
+///
/// - width: Rel<Length> (named)
/// The shape's width.
+///
/// - height: Rel<Length> (named)
/// The shape's height.
+///
/// - size: Length (named)
/// The square's side length.
+///
/// - radius: Length (named)
/// The circle's radius.
+///
/// - stroke: Smart<Sides<Option<PartialStroke>>> (named)
/// How to stroke the shape.
///
diff --git a/macros/src/func.rs b/macros/src/func.rs
index 98fca6a4..62fbfd72 100644
--- a/macros/src/func.rs
+++ b/macros/src/func.rs
@@ -1,4 +1,3 @@
-use proc_macro2::Span;
use unscanny::Scanner;
use super::*;
@@ -14,12 +13,21 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
let tags = tags(&mut docs);
let params = params(&mut docs)?;
+ let example = quote_option(example(&mut docs));
+ let syntax = quote_option(section(&mut docs, "Syntax"));
+
let docs = docs.trim();
+ if docs.contains("# ") {
+ bail!(item, "Documentation heading not recognized");
+ }
+
let info = quote! {
::typst::model::FuncInfo {
name,
- docs: #docs,
tags: &[#(#tags),*],
+ docs: #docs,
+ example: #example,
+ syntax: #syntax,
params: ::std::vec![#(#params),*],
}
};
@@ -76,18 +84,18 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
/// Extract a section.
pub fn section(docs: &mut String, title: &str) -> Option<String> {
- let needle = format!("# {title}\n");
+ let needle = format!("\n# {title}\n");
let start = docs.find(&needle)?;
let rest = &docs[start..];
- let len = rest[1..].find('#').map(|x| 1 + x).unwrap_or(rest.len());
+ let len = rest[1..].find("\n# ").map(|x| 1 + x).unwrap_or(rest.len());
let end = start + len;
- let section = docs[start + needle.len()..].to_owned();
+ let section = docs[start + needle.len()..end].trim().to_owned();
docs.replace_range(start..end, "");
Some(section)
}
/// Parse the tag section.
-pub fn tags(docs: &mut String) -> Vec<String> {
+fn tags(docs: &mut String) -> Vec<String> {
section(docs, "Tags")
.unwrap_or_default()
.lines()
@@ -96,24 +104,40 @@ pub fn tags(docs: &mut String) -> Vec<String> {
.collect()
}
+/// Parse the example section.
+pub fn example(docs: &mut String) -> Option<String> {
+ Some(
+ section(docs, "Example")?
+ .lines()
+ .skip_while(|line| !line.contains("```"))
+ .skip(1)
+ .take_while(|line| !line.contains("```"))
+ .map(|s| s.trim())
+ .collect::<Vec<_>>()
+ .join("\n"),
+ )
+}
+
/// Parse the parameter section.
-pub fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
+fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
let Some(section) = section(docs, "Parameters") else { return Ok(vec![]) };
let mut s = Scanner::new(&section);
let mut infos = vec![];
while s.eat_if('-') {
- s.eat_whitespace();
- let name = s.eat_until(':');
- s.expect(": ");
- let ty: syn::Type = syn::parse_str(s.eat_until(char::is_whitespace))?;
- s.eat_whitespace();
let mut named = false;
let mut positional = false;
let mut required = false;
let mut variadic = false;
let mut settable = false;
+
+ s.eat_whitespace();
+ let name = s.eat_until(':');
+ s.expect(": ");
+ let ty: syn::Type = syn::parse_str(s.eat_until(char::is_whitespace))?;
+ s.eat_whitespace();
s.expect('(');
+
for part in s.eat_until(')').split(',').map(str::trim).filter(|s| !s.is_empty()) {
match part {
"named" => named = true,
@@ -121,12 +145,7 @@ pub fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
"required" => required = true,
"variadic" => variadic = true,
"settable" => settable = true,
- _ => {
- return Err(syn::Error::new(
- Span::call_site(),
- format!("unknown parameter flag {:?}", part),
- ))
- }
+ _ => bail!(callsite, "unknown parameter flag {:?}", part),
}
}
@@ -135,18 +154,20 @@ pub fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
|| (named && variadic)
|| (required && variadic)
{
- return Err(syn::Error::new(
- Span::call_site(),
- "invalid combination of parameter flags",
- ));
+ bail!(callsite, "invalid combination of parameter flags");
}
s.expect(')');
- let docs = dedent(s.eat_until("\n-").trim());
+
+ let mut docs = dedent(s.eat_until("\n-").trim());
+ let example = quote_option(example(&mut docs));
+ let docs = docs.trim();
+
infos.push(quote! {
::typst::model::ParamInfo {
name: #name,
docs: #docs,
+ example: #example,
cast: <#ty as ::typst::model::Cast<
::typst::syntax::Spanned<::typst::model::Value>
>>::describe(),
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index a03dc30e..23b03712 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -4,12 +4,18 @@ extern crate proc_macro;
/// Return an error at the given item.
macro_rules! bail {
+ (callsite, $fmt:literal $($tts:tt)*) => {
+ return Err(syn::Error::new(
+ proc_macro2::Span::call_site(),
+ format!(concat!("typst: ", $fmt) $($tts)*)
+ ))
+ };
($item:expr, $fmt:literal $($tts:tt)*) => {
- return Err(Error::new_spanned(
+ return Err(syn::Error::new_spanned(
&$item,
format!(concat!("typst: ", $fmt) $($tts)*)
))
- }
+ };
}
mod capable;
@@ -19,9 +25,8 @@ mod node;
use proc_macro::TokenStream as BoundaryStream;
use proc_macro2::{TokenStream, TokenTree};
-use quote::{quote, quote_spanned};
-use syn::parse_quote;
-use syn::{Error, Ident, Result};
+use quote::{quote, quote_spanned, ToTokens};
+use syn::{parse_quote, Ident, Result};
/// Implement `FuncType` for a type or function.
#[proc_macro_attribute]
@@ -88,3 +93,11 @@ fn documentation(attrs: &[syn::Attribute]) -> String {
fn dedent(text: &str) -> String {
text.lines().map(str::trim).collect::<Vec<_>>().join("\n")
}
+
+/// Quote an optional value.
+fn quote_option<T: ToTokens>(option: Option<T>) -> TokenStream {
+ match option {
+ Some(value) => quote! { Some(#value) },
+ None => quote! { None },
+ }
+}
diff --git a/macros/src/node.rs b/macros/src/node.rs
index 1e03c441..5f9573f9 100644
--- a/macros/src/node.rs
+++ b/macros/src/node.rs
@@ -333,13 +333,18 @@ fn create_node_set_func(node: &Node) -> syn::ImplItemMethod {
fn create_node_properties_func(node: &Node) -> syn::ImplItemMethod {
let infos = node.properties.iter().filter(|p| !p.skip).map(|property| {
let name = property.name.to_string().replace('_', "-").to_lowercase();
- let docs = documentation(&property.attrs);
let value_ty = &property.value_ty;
let shorthand = matches!(property.shorthand, Some(Shorthand::Positional));
+
+ let mut docs = documentation(&property.attrs);
+ let example = quote_option(super::func::example(&mut docs));
+ let docs = docs.trim();
+
quote! {
::typst::model::ParamInfo {
name: #name,
docs: #docs,
+ example: #example,
cast: <#value_ty as ::typst::model::Cast<
::typst::syntax::Spanned<::typst::model::Value>
>>::describe(),
diff --git a/src/font/book.rs b/src/font/book.rs
index 2ad30f1d..38dfee1d 100644
--- a/src/font/book.rs
+++ b/src/font/book.rs
@@ -170,7 +170,7 @@ bitflags::bitflags! {
impl FontInfo {
/// Compute metadata for all fonts in the given data.
- pub fn from_data(data: &[u8]) -> impl Iterator<Item = FontInfo> + '_ {
+ pub fn iter(data: &[u8]) -> impl Iterator<Item = FontInfo> + '_ {
let count = ttf_parser::fonts_in_collection(data).unwrap_or(1);
(0..count).filter_map(move |index| {
let ttf = ttf_parser::Face::parse(data, index).ok()?;
@@ -179,7 +179,7 @@ impl FontInfo {
}
/// Compute metadata for a single ttf-parser face.
- pub fn from_ttf(ttf: &ttf_parser::Face) -> Option<Self> {
+ pub(super) fn from_ttf(ttf: &ttf_parser::Face) -> Option<Self> {
// We cannot use Name ID 16 "Typographic Family", because for some
// fonts it groups together more than just Style / Weight / Stretch
// variants (e.g. Display variants of Noto fonts) and then some
diff --git a/src/font/mod.rs b/src/font/mod.rs
index 98875d8f..13189b6d 100644
--- a/src/font/mod.rs
+++ b/src/font/mod.rs
@@ -69,6 +69,12 @@ impl Font {
})))
}
+ /// Parse all fonts in the given data.
+ pub fn iter(data: Buffer) -> impl Iterator<Item = Self> {
+ let count = ttf_parser::fonts_in_collection(&data).unwrap_or(1);
+ (0..count).filter_map(move |index| Self::new(data.clone(), index))
+ }
+
/// The underlying buffer.
pub fn data(&self) -> &Buffer {
&self.0.data
diff --git a/src/model/func.rs b/src/model/func.rs
index 46befd77..fb8b3dd0 100644
--- a/src/model/func.rs
+++ b/src/model/func.rs
@@ -214,6 +214,10 @@ pub struct FuncInfo {
pub tags: &'static [&'static str],
/// Documentation for the function.
pub docs: &'static str,
+ /// The source code of an example, if any.
+ pub example: Option<&'static str>,
+ /// Documentation about this function's syntax, if it has syntax.
+ pub syntax: Option<&'static str>,
/// Details about the function's parameters.
pub params: Vec<ParamInfo>,
}
@@ -232,6 +236,8 @@ pub struct ParamInfo {
pub name: &'static str,
/// Documentation for the parameter.
pub docs: &'static str,
+ /// The source code of an example, if any.
+ pub example: Option<&'static str>,
/// Valid values for the parameter.
pub cast: CastInfo,
/// Is the parameter positional?
diff --git a/src/model/library.rs b/src/model/library.rs
index 83310610..8b767b0e 100644
--- a/src/model/library.rs
+++ b/src/model/library.rs
@@ -122,7 +122,7 @@ pub static LANG_ITEMS: OnceCell<LangItems> = OnceCell::new();
/// break incremental, but only when different sets of lang items are used in
/// the same program. For this reason, if this function is called multiple
/// times, the items must be the same.
-pub(crate) fn set_lang_items(items: LangItems) {
+pub fn set_lang_items(items: LangItems) {
if let Err(items) = LANG_ITEMS.set(items) {
let first = hash128(LANG_ITEMS.get().unwrap());
let second = hash128(&items);
diff --git a/tests/src/tests.rs b/tests/src/tests.rs
index 7c1e39b7..7316ed11 100644
--- a/tests/src/tests.rs
+++ b/tests/src/tests.rs
@@ -213,10 +213,8 @@ impl TestWorld {
.filter_map(|e| e.ok())
.filter(|entry| entry.file_type().is_file())
{
- let buffer: Buffer = fs::read(entry.path()).unwrap().into();
- for index in 0..ttf_parser::fonts_in_collection(&buffer).unwrap_or(1) {
- fonts.push(Font::new(buffer.clone(), index).unwrap())
- }
+ let data = std::fs::read(entry.path()).unwrap();
+ fonts.extend(Font::iter(data.into()));
}
Self {