mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Documentation
This commit is contained in:
parent
b8ffd3ad3d
commit
f5f7df7247
@ -5,30 +5,48 @@ use crate::layout::{BlockNode, VNode};
|
||||
use crate::prelude::*;
|
||||
use crate::text::{SpaceNode, TextNode, TextSize};
|
||||
|
||||
/// # Heading
|
||||
/// A section heading.
|
||||
///
|
||||
/// # Example
|
||||
/// With headings, you can structure your document into sections. Each heading
|
||||
/// has a _level,_ which starts at one and is unbounded upwards. This level
|
||||
/// indicates the logical role of the following content (section, subsection,
|
||||
/// etc.) Top-level heading indicates a top-level section of the document (not
|
||||
/// the document's title).
|
||||
///
|
||||
/// Typst can automatically number your headings for you. To enable numbering,
|
||||
/// specify how you want your headings to be numbered with a [numbering
|
||||
/// pattern](@numbering).
|
||||
///
|
||||
/// Independently from the numbering, Typst can also automatically generate an
|
||||
/// [outline](@outline) of all headings for you. To exclude one or more headings
|
||||
/// from this outline, you can set the `outlined` parameter to `{false}`.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #set heading(numbering: "I.")
|
||||
/// #set heading(numbering: "1.a)")
|
||||
///
|
||||
/// = Introduction
|
||||
/// In recent years, ...
|
||||
///
|
||||
/// == Preliminaries
|
||||
/// To start, ...
|
||||
/// ```
|
||||
///
|
||||
/// # 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.
|
||||
/// ## Syntax
|
||||
/// Headings have dedicated syntax: They can be created by starting a line with
|
||||
/// one or multiple equals signs, followed by a space. The number of equals
|
||||
/// signs determines the heading's logical nesting depth.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The heading's contents.
|
||||
/// ## Parameters
|
||||
/// - title: Content (positional, required)
|
||||
/// The heading's title.
|
||||
///
|
||||
/// - level: NonZeroUsize (named)
|
||||
/// The logical nesting depth of the heading, starting from one.
|
||||
///
|
||||
/// # Tags
|
||||
/// - basics
|
||||
/// ## Category
|
||||
/// basics
|
||||
#[func]
|
||||
#[capable(Prepare, Show, Finalize)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -37,12 +55,12 @@ pub struct HeadingNode {
|
||||
/// default style, this controls the text size of the heading.
|
||||
pub level: NonZeroUsize,
|
||||
/// The heading's contents.
|
||||
pub body: Content,
|
||||
pub title: Content,
|
||||
}
|
||||
|
||||
#[node]
|
||||
impl HeadingNode {
|
||||
/// How to number the heading.
|
||||
/// How to number the heading. Accepts a [numbering pattern](@numbering).
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
@ -72,7 +90,7 @@ impl HeadingNode {
|
||||
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self {
|
||||
body: args.expect("body")?,
|
||||
title: args.expect("title")?,
|
||||
level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()),
|
||||
}
|
||||
.pack())
|
||||
@ -81,7 +99,7 @@ impl HeadingNode {
|
||||
fn field(&self, name: &str) -> Option<Value> {
|
||||
match name {
|
||||
"level" => Some(Value::Int(self.level.get() as i64)),
|
||||
"body" => Some(Value::Content(self.body.clone())),
|
||||
"title" => Some(Value::Content(self.title.clone())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -118,7 +136,7 @@ impl Prepare for HeadingNode {
|
||||
|
||||
impl Show for HeadingNode {
|
||||
fn show(&self, _: &mut Vt, this: &Content, _: StyleChain) -> SourceResult<Content> {
|
||||
let mut realized = self.body.clone();
|
||||
let mut realized = self.title.clone();
|
||||
if let Some(Value::Str(numbering)) = this.field("numbers") {
|
||||
realized = TextNode::packed(numbering) + SpaceNode.pack() + realized;
|
||||
}
|
||||
|
@ -3,9 +3,10 @@ use crate::layout::{BlockNode, GridNode, HNode, ParNode, Spacing, TrackSizing};
|
||||
use crate::prelude::*;
|
||||
use crate::text::{SpaceNode, TextNode};
|
||||
|
||||
/// # List
|
||||
/// An unordered (bulleted) or ordered (numbered) list.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - items: Content (positional, variadic)
|
||||
/// The contents of the list items.
|
||||
///
|
||||
@ -16,7 +17,7 @@ use crate::text::{SpaceNode, TextNode};
|
||||
/// Makes the list more compact, if enabled. This looks better if the items
|
||||
/// fit into a single line each.
|
||||
///
|
||||
/// # Example
|
||||
/// ### Example
|
||||
/// ```
|
||||
/// #show columns.with(2)
|
||||
/// #list(tight: true)[Tight][List]
|
||||
@ -24,8 +25,8 @@ use crate::text::{SpaceNode, TextNode};
|
||||
/// #list(tight: false)[Wide][List]
|
||||
/// ```
|
||||
///
|
||||
/// # Tags
|
||||
/// - basics
|
||||
/// ## Category
|
||||
/// basics
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::layout::{GridNode, TrackSizing, TrackSizings};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Table
|
||||
/// A table of items.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - cells: Content (positional, variadic)
|
||||
/// The contents of the table cells.
|
||||
///
|
||||
@ -22,8 +23,8 @@ use crate::prelude::*;
|
||||
/// - row-gutter: TrackSizings (named)
|
||||
/// Defines the gaps between rows. Takes precedence over `gutter`.
|
||||
///
|
||||
/// # Tags
|
||||
/// - basics
|
||||
/// ## Category
|
||||
/// basics
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,14 +2,22 @@ use std::cmp::Ordering;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Absolute
|
||||
/// The absolute value of a numeric value.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #abs(-5) \
|
||||
/// #abs(5pt - 2cm) \
|
||||
/// #abs(2fr)
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: ToAbs (positional, required)
|
||||
/// The value whose absolute value to calculate.
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn abs(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(args.expect::<ToAbs>("value")?.0)
|
||||
@ -22,32 +30,50 @@ castable! {
|
||||
ToAbs,
|
||||
v: i64 => Self(Value::Int(v.abs())),
|
||||
v: f64 => Self(Value::Float(v.abs())),
|
||||
v: Length => Self(Value::Length(v.try_abs()
|
||||
.ok_or_else(|| "cannot take absolute value of this length")?)),
|
||||
v: Angle => Self(Value::Angle(v.abs())),
|
||||
v: Ratio => Self(Value::Ratio(v.abs())),
|
||||
v: Fr => Self(Value::Fraction(v.abs())),
|
||||
}
|
||||
|
||||
/// # Minimum
|
||||
/// The minimum of a sequence of values.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - values: Value (positional, variadic)
|
||||
/// The sequence of values.
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #min(1, -3, -5, 20, 3, 6) \
|
||||
/// #min("Typst", "in", "beta")
|
||||
/// ```
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Parameters
|
||||
/// - values: Value (positional, variadic)
|
||||
/// The sequence of values from which to extract the minimum.
|
||||
/// Must not be empty.
|
||||
///
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn min(args: &mut Args) -> SourceResult<Value> {
|
||||
minmax(args, Ordering::Less)
|
||||
}
|
||||
|
||||
/// # Maximum
|
||||
/// The maximum of a sequence of values.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - values: Value (positional, variadic)
|
||||
/// The sequence of values.
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #max(1, -3, -5, 20, 3, 6) \
|
||||
/// #max("Typst", "in", "beta")
|
||||
/// ```
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Parameters
|
||||
/// - values: Value (positional, variadic)
|
||||
/// The sequence of values from which to extract the maximum.
|
||||
/// Must not be empty.
|
||||
///
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn max(args: &mut Args) -> SourceResult<Value> {
|
||||
minmax(args, Ordering::Greater)
|
||||
@ -74,43 +100,67 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> {
|
||||
Ok(extremum)
|
||||
}
|
||||
|
||||
/// # Even
|
||||
/// Whether an integer is even.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #even(4) \
|
||||
/// #even(5) \
|
||||
/// { range(10).filter(even) }
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: i64 (positional, required)
|
||||
/// The number to check for evenness.
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn even(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Bool(args.expect::<i64>("value")? % 2 == 0))
|
||||
}
|
||||
|
||||
/// # Odd
|
||||
/// Whether an integer is odd.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #odd(4) \
|
||||
/// #odd(5) \
|
||||
/// { range(10).filter(odd) }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: i64 (positional, required)
|
||||
/// The number to check for oddness.
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn odd(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Bool(args.expect::<i64>("value")? % 2 != 0))
|
||||
}
|
||||
|
||||
/// # Modulus
|
||||
/// The modulus of two numbers.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #mod(20, 6) \
|
||||
/// #mod(1.75, 0.5)
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - dividend: ToMod (positional, required)
|
||||
/// The dividend of the modulus.
|
||||
///
|
||||
/// - divisor: ToMod (positional, required)
|
||||
/// The divisor of the modulus.
|
||||
///
|
||||
/// # Tags
|
||||
/// - calculate
|
||||
/// ## Category
|
||||
/// calculate
|
||||
#[func]
|
||||
pub fn mod_(args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v: v1, span: span1 } = args.expect("dividend")?;
|
||||
|
@ -4,14 +4,27 @@ use typst::model::Regex;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Integer
|
||||
/// Convert a value to an integer.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - Booleans are converted to `0` or `1`.
|
||||
/// - Floats are floored to the next 64-bit integer.
|
||||
/// - Strings are parsed in base 10.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #int(false) \
|
||||
/// #int(true) \
|
||||
/// #int(2.7) \
|
||||
/// { int("27") + int("4") }
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: ToInt (positional, required)
|
||||
/// The value that should be converted to an integer.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn int(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Int(args.expect::<ToInt>("value")?.0))
|
||||
@ -28,14 +41,29 @@ castable! {
|
||||
v: EcoString => Self(v.parse().map_err(|_| "not a valid integer")?),
|
||||
}
|
||||
|
||||
/// # Float
|
||||
/// Convert a value to a float.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - Booleans are converted to `0.0` or `1.0`.
|
||||
/// - Integers are converted to the closest 64-bit float.
|
||||
/// - Strings are parsed in base 10 to the closest 64-bit float.
|
||||
/// Exponential notation is supported.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #float(false) \
|
||||
/// #float(true) \
|
||||
/// #float(4) \
|
||||
/// #float("2.7") \
|
||||
/// #float("1e5")
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: ToFloat (positional, required)
|
||||
/// The value that should be converted to a float.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn float(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Float(args.expect::<ToFloat>("value")?.0))
|
||||
@ -52,23 +80,45 @@ castable! {
|
||||
v: EcoString => Self(v.parse().map_err(|_| "not a valid float")?),
|
||||
}
|
||||
|
||||
/// # Luma
|
||||
/// Create a grayscale color.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #for x in range(250, step: 50) {
|
||||
/// square(fill: luma(x))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - gray: Component (positional, required)
|
||||
/// The gray component.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
||||
let Component(luma) = args.expect("gray component")?;
|
||||
Ok(Value::Color(LumaColor::new(luma).into()))
|
||||
}
|
||||
|
||||
/// # RGBA
|
||||
/// Create an RGB(A) color.
|
||||
///
|
||||
/// # Parameters
|
||||
/// The color is specified in the sRGB color space.
|
||||
///
|
||||
/// _Note:_ While you can specify transparent colors and Typst's preview will
|
||||
/// render them correctly, the PDF export does not handle them properly at the
|
||||
/// moment. This will be fixed in the future.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #square(fill: rgb("#b1f2eb"))
|
||||
/// #square(fill: rgb(87, 127, 230))
|
||||
/// #square(fill: rgb(25%, 13%, 65%))
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - hex: EcoString (positional)
|
||||
/// The color in hexademical notation.
|
||||
///
|
||||
@ -77,10 +127,11 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
||||
///
|
||||
/// If this string is given, the individual components should not be given.
|
||||
///
|
||||
/// # Example
|
||||
/// ### Example
|
||||
/// ```
|
||||
/// #let color = rgb("#239dad")
|
||||
/// #text(16pt, color)[*Typst*]
|
||||
/// #text(16pt, rgb("#239dad"))[
|
||||
/// *Typst*
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// - red: Component (positional)
|
||||
@ -95,8 +146,8 @@ pub fn luma(args: &mut Args) -> SourceResult<Value> {
|
||||
/// - alpha: Component (positional)
|
||||
/// The alpha component.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn rgb(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||
@ -129,9 +180,21 @@ castable! {
|
||||
},
|
||||
}
|
||||
|
||||
/// # CMYK
|
||||
/// Create a CMYK color.
|
||||
///
|
||||
/// # Parameters
|
||||
/// This is useful if you want to target a specific printer. The conversion
|
||||
/// to RGB for display preview might differ from how your printer reproduces
|
||||
/// the color.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #square(
|
||||
/// fill: cmyk(27%, 0%, 3%, 5%)
|
||||
/// )
|
||||
/// ````
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - cyan: RatioComponent (positional, required)
|
||||
/// The cyan component.
|
||||
///
|
||||
@ -144,8 +207,8 @@ castable! {
|
||||
/// - key: RatioComponent (positional, required)
|
||||
/// The key component.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn cmyk(args: &mut Args) -> SourceResult<Value> {
|
||||
let RatioComponent(c) = args.expect("cyan component")?;
|
||||
@ -167,14 +230,27 @@ castable! {
|
||||
},
|
||||
}
|
||||
|
||||
/// # String
|
||||
/// Convert a value to a string.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - Integers are formatted in base 10.
|
||||
/// - Floats are formatted in base 10 and never in exponential notation.
|
||||
/// - From labels the name is extracted.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #str(10) \
|
||||
/// #str(2.7) \
|
||||
/// #str(1e8) \
|
||||
/// #str(<intro>)
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - value: ToStr (positional, required)
|
||||
/// The value that should be converted to a string.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn str(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Str(args.expect::<ToStr>("value")?.0))
|
||||
@ -191,36 +267,94 @@ castable! {
|
||||
v: Str => Self(v),
|
||||
}
|
||||
|
||||
/// # Label
|
||||
/// Create a label from a string.
|
||||
///
|
||||
/// # Parameters
|
||||
/// Inserting a label into content attaches it to the closest previous element
|
||||
/// that is not a space. Then, the element can be [referenced](@ref) and styled
|
||||
/// through the label.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #show <a>: set text(blue)
|
||||
/// #show label("b"): set text(red)
|
||||
///
|
||||
/// = Heading <a>
|
||||
/// *Strong* #label("b")
|
||||
/// ```
|
||||
///
|
||||
/// ## Syntax
|
||||
/// 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.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn label(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::Label(Label(args.expect("string")?)))
|
||||
}
|
||||
|
||||
/// # Regex
|
||||
/// Create a regular expression from a string.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - regex: EcoString (positional, required)
|
||||
/// The regular expression.
|
||||
/// The result can be used as a show rule
|
||||
/// [selector](/docs/reference/concepts/#selector) and with
|
||||
/// [string methods](/docs/reference/concepts/#methods) like `find`, `split`,
|
||||
/// and `replace`.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// [See here](https://docs.rs/regex/latest/regex/#syntax) for a specification
|
||||
/// of the supported syntax.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// // Works with show rules.
|
||||
/// #show regex("\d+"): set text(red)
|
||||
///
|
||||
/// The numbers 1 to 10.
|
||||
///
|
||||
/// // Works with string methods.
|
||||
/// { "a,b;c"
|
||||
/// .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("\\\\")}`.
|
||||
///
|
||||
/// ## Category
|
||||
/// create
|
||||
#[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())
|
||||
}
|
||||
|
||||
/// # Range
|
||||
/// Create an array consisting of a sequence of numbers.
|
||||
///
|
||||
/// # Parameters
|
||||
/// If you pass just one positional parameter, it is interpreted as the `end` of
|
||||
/// the range. If you pass two, they describe the `start` and `end` of the
|
||||
/// range.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #range(5) \
|
||||
/// #range(2, 5) \
|
||||
/// #range(20, step: 4) \
|
||||
/// #range(21, step: 4) \
|
||||
/// #range(5, 2, step: -1)
|
||||
/// ```
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - start: i64 (positional)
|
||||
/// The start of the range (inclusive).
|
||||
///
|
||||
@ -230,8 +364,8 @@ pub fn regex(args: &mut Args) -> SourceResult<Value> {
|
||||
/// - step: i64 (named)
|
||||
/// The distance between the generated numbers.
|
||||
///
|
||||
/// # Tags
|
||||
/// - create
|
||||
/// ## Category
|
||||
/// create
|
||||
#[func]
|
||||
pub fn range(args: &mut Args) -> SourceResult<Value> {
|
||||
let first = args.expect::<i64>("end")?;
|
||||
|
@ -4,6 +4,7 @@ use typst::diag::{format_xml_like_error, FileError};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # CSV
|
||||
/// Read structured data from a CSV file.
|
||||
///
|
||||
/// The CSV file will be read and parsed into a 2-dimensional array of strings:
|
||||
@ -11,7 +12,7 @@ use crate::prelude::*;
|
||||
/// rows will be collected into a single array. Header rows will not be
|
||||
/// stripped.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #let results = csv("/data.csv")
|
||||
///
|
||||
@ -21,7 +22,8 @@ use crate::prelude::*;
|
||||
/// ..results.flatten(),
|
||||
/// )
|
||||
/// ```
|
||||
/// # Parameters
|
||||
///
|
||||
/// ## Parameters
|
||||
/// - path: EcoString (positional, required)
|
||||
/// Path to a CSV file.
|
||||
/// - delimiter: Delimiter (named)
|
||||
@ -29,8 +31,8 @@ use crate::prelude::*;
|
||||
/// Must be a single ASCII character.
|
||||
/// Defaults to a comma.
|
||||
///
|
||||
/// # Tags
|
||||
/// - data-loading
|
||||
/// ## Category
|
||||
/// data-loading
|
||||
#[func]
|
||||
pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v: path, span } =
|
||||
@ -95,6 +97,7 @@ fn format_csv_error(error: csv::Error) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// # JSON
|
||||
/// Read structured data from a JSON file.
|
||||
///
|
||||
/// The file must contain a valid JSON object or array. JSON objects will be
|
||||
@ -108,7 +111,7 @@ fn format_csv_error(error: csv::Error) -> String {
|
||||
/// The JSON files in the example contain a object with the keys `temperature`,
|
||||
/// `unit`, and `weather`.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #let forecast(day) = block[
|
||||
/// #square(
|
||||
@ -134,12 +137,12 @@ fn format_csv_error(error: csv::Error) -> String {
|
||||
/// #forecast(json("/tuesday.json"))
|
||||
/// ```
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - path: EcoString (positional, required)
|
||||
/// Path to a JSON file.
|
||||
///
|
||||
/// # Tags
|
||||
/// - data-loading
|
||||
/// ## Category
|
||||
/// data-loading
|
||||
#[func]
|
||||
pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v: path, span } =
|
||||
@ -177,12 +180,10 @@ fn convert_json(value: serde_json::Value) -> Value {
|
||||
/// Format the user-facing JSON error message.
|
||||
fn format_json_error(error: serde_json::Error) -> String {
|
||||
assert!(error.is_syntax() || error.is_eof());
|
||||
format!(
|
||||
"failed to parse json file: syntax error in line {}",
|
||||
error.line()
|
||||
)
|
||||
format!("failed to parse json file: syntax error in line {}", error.line())
|
||||
}
|
||||
|
||||
/// # XML
|
||||
/// Read structured data from an XML file.
|
||||
///
|
||||
/// The XML file is parsed into an array of dictionaries and strings. XML nodes
|
||||
@ -198,7 +199,7 @@ fn format_json_error(error: serde_json::Error) -> String {
|
||||
/// `content` tag contains one or more paragraphs, which are represented as `p`
|
||||
/// tags.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #let findChild(elem, tag) = {
|
||||
/// elem.children
|
||||
@ -232,12 +233,12 @@ fn format_json_error(error: serde_json::Error) -> String {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - path: EcoString (positional, required)
|
||||
/// Path to an XML file.
|
||||
///
|
||||
/// # Tags
|
||||
/// - data-loading
|
||||
/// ## Category
|
||||
/// data-loading
|
||||
#[func]
|
||||
pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v: path, span } =
|
||||
|
@ -4,40 +4,43 @@ use comemo::Track;
|
||||
use typst::model;
|
||||
use typst::syntax::Source;
|
||||
|
||||
/// # Type
|
||||
/// The name of a value's type.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - value: Value (positional, required)
|
||||
/// The value whose type's to determine.
|
||||
///
|
||||
/// # Tags
|
||||
/// - foundations
|
||||
/// ## Category
|
||||
/// foundations
|
||||
#[func]
|
||||
pub fn type_(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(args.expect::<Value>("value")?.type_name().into())
|
||||
}
|
||||
|
||||
/// # Representation
|
||||
/// The string representation of a value.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - value: Value (positional, required)
|
||||
/// The value whose string representation to produce.
|
||||
///
|
||||
/// # Tags
|
||||
/// - foundations
|
||||
/// ## Category
|
||||
/// foundations
|
||||
#[func]
|
||||
pub fn repr(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(args.expect::<Value>("value")?.repr().into())
|
||||
}
|
||||
|
||||
/// # Assert
|
||||
/// Ensure that a condition is fulfilled.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - condition: bool (positional, required)
|
||||
/// The condition that must be true for the assertion to pass.
|
||||
///
|
||||
/// # Tags
|
||||
/// - foundations
|
||||
/// ## Category
|
||||
/// foundations
|
||||
#[func]
|
||||
pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
||||
@ -47,14 +50,15 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
||||
/// # Evaluate
|
||||
/// Evaluate a string as Typst markup.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - source: String (positional, required)
|
||||
/// A string of Typst markup to evaluate.
|
||||
///
|
||||
/// # Tags
|
||||
/// - foundations
|
||||
/// ## Category
|
||||
/// foundations
|
||||
#[func]
|
||||
pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
|
||||
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
||||
|
@ -3,31 +3,33 @@ use std::str::FromStr;
|
||||
use crate::prelude::*;
|
||||
use crate::text::Case;
|
||||
|
||||
/// # Blind Text
|
||||
/// Create blind text.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - words: usize (positional, required)
|
||||
/// The length of the blind text in words.
|
||||
///
|
||||
/// # Tags
|
||||
/// - utility
|
||||
/// ## Category
|
||||
/// utility
|
||||
#[func]
|
||||
pub fn lorem(args: &mut Args) -> SourceResult<Value> {
|
||||
let words: usize = args.expect("number of words")?;
|
||||
Ok(Value::Str(lipsum::lipsum(words).into()))
|
||||
}
|
||||
|
||||
/// # Numbering
|
||||
/// Apply a numbering pattern to a sequence of numbers.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - pattern: NumberingPattern (positional, required)
|
||||
/// A string that defines how the numbering works.
|
||||
///
|
||||
/// - numbers: NonZeroUsize (positional, variadic)
|
||||
/// The numbers to apply the pattern to.
|
||||
///
|
||||
/// # Tags
|
||||
/// - utility
|
||||
/// ## Category
|
||||
/// utility
|
||||
#[func]
|
||||
pub fn numbering(args: &mut Args) -> SourceResult<Value> {
|
||||
let pattern = args.expect::<NumberingPattern>("pattern")?;
|
||||
|
@ -1,16 +1,17 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Align
|
||||
/// Align content horizontally and vertically.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to align.
|
||||
///
|
||||
/// - alignment: Axes<Option<GenAlign>> (positional, settable)
|
||||
/// The alignment along both axes.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,17 +1,18 @@
|
||||
use crate::prelude::*;
|
||||
use crate::text::TextNode;
|
||||
|
||||
/// # Columns
|
||||
/// Separate a region into multiple equally sized columns.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - count: usize (positional, required)
|
||||
/// The number of columns.
|
||||
///
|
||||
/// - body: Content (positional, required)
|
||||
/// The content that should be layouted into the columns.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -112,15 +113,16 @@ impl Layout for ColumnsNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Column Break
|
||||
/// A column break.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - weak: bool (named)
|
||||
/// If true, the column break is skipped if the current column is already
|
||||
/// empty.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Behave)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,9 +2,10 @@ use super::VNode;
|
||||
use crate::layout::Spacing;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Box
|
||||
/// An inline-level container that sizes content.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional)
|
||||
/// The contents of the box.
|
||||
///
|
||||
@ -14,8 +15,8 @@ use crate::prelude::*;
|
||||
/// - height: Rel<Length> (named)
|
||||
/// The height of the box.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -75,9 +76,10 @@ impl Layout for BoxNode {
|
||||
|
||||
impl Inline for BoxNode {}
|
||||
|
||||
/// # Block
|
||||
/// A block-level container that places content into a separate flow.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional)
|
||||
/// The contents of the block.
|
||||
///
|
||||
@ -92,8 +94,8 @@ impl Inline for BoxNode {}
|
||||
/// The spacing between this block and the following one. Takes precedence
|
||||
/// over `spacing`.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,9 +2,10 @@ use crate::prelude::*;
|
||||
|
||||
use super::Spacing;
|
||||
|
||||
/// # Grid
|
||||
/// Arrange content in a grid.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - cells: Content (positional, variadic)
|
||||
/// The contents of the table cells.
|
||||
///
|
||||
@ -23,8 +24,8 @@ use super::Spacing;
|
||||
/// - row-gutter: TrackSizings (named)
|
||||
/// Defines the gaps between rows. Takes precedence over `gutter`.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,13 +1,14 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Hide
|
||||
/// Hide content without affecting layout.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to hide.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Padding
|
||||
/// Pad content at the sides.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to pad at the sides.
|
||||
///
|
||||
@ -27,8 +28,8 @@ use crate::prelude::*;
|
||||
/// - rest: Rel<Length> (named)
|
||||
/// The padding for all sides. All other parameters take precedence over this.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -4,17 +4,18 @@ use super::ColumnsNode;
|
||||
use crate::prelude::*;
|
||||
use crate::text::TextNode;
|
||||
|
||||
/// # Page
|
||||
/// Layouts its child onto one or multiple pages.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The contents of the page(s).
|
||||
///
|
||||
/// - paper: Paper (positional, settable)
|
||||
/// The paper size.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Clone, Hash)]
|
||||
@ -154,14 +155,15 @@ impl Debug for PageNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Page Break
|
||||
/// A page break.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - weak: bool (named)
|
||||
/// If true, the page break is skipped if the current page is already empty.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
|
@ -11,14 +11,15 @@ use crate::text::{
|
||||
shape, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode, TextNode,
|
||||
};
|
||||
|
||||
/// # Paragraph
|
||||
/// Arrange text, spacing and inline-level nodes into a paragraph.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The contents of the paragraph.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Hash)]
|
||||
@ -147,10 +148,11 @@ castable! {
|
||||
"optimized" => Self::Optimized,
|
||||
}
|
||||
|
||||
/// # Paragraph Break
|
||||
/// A paragraph break.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Unlabellable)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Place
|
||||
/// Place content at an absolute position.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - alignment: Axes<Option<GenAlign>> (positional)
|
||||
/// Relative to which position in the parent container to place the content.
|
||||
///
|
||||
@ -15,8 +16,8 @@ use crate::prelude::*;
|
||||
/// - dy: Rel<Length> (named)
|
||||
/// The vertical displacement of the placed content.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Behave)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,13 +1,14 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Repeat
|
||||
/// Repeats content to fill a line.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to repeat.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,9 +2,10 @@ use std::cmp::Ordering;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Spacing (H)
|
||||
/// Horizontal spacing in a paragraph.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - amount: Spacing (positional, required)
|
||||
/// How much spacing to insert.
|
||||
///
|
||||
@ -13,8 +14,8 @@ use crate::prelude::*;
|
||||
/// Moreover, from multiple adjacent weak spacings all but the largest one
|
||||
/// collapse.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Behave)]
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
@ -63,9 +64,10 @@ impl Behave for HNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Spacing (V)
|
||||
/// Vertical spacing.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - amount: Spacing (positional, required)
|
||||
/// How much spacing to insert.
|
||||
///
|
||||
@ -74,8 +76,8 @@ impl Behave for HNode {
|
||||
/// Moreover, from multiple adjacent weak spacings all but the largest one
|
||||
/// collapse.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Behave)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd)]
|
||||
|
@ -3,9 +3,10 @@ use typst::model::StyledNode;
|
||||
use super::{AlignNode, Spacing};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Stack
|
||||
/// Arrange content and spacing along an axis.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - items: StackChild (positional, variadic)
|
||||
/// The items to stack along an axis.
|
||||
///
|
||||
@ -15,8 +16,8 @@ use crate::prelude::*;
|
||||
/// - spacing: Spacing (named)
|
||||
/// Spacing to insert between items where no explicit spacing was provided.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,9 +2,10 @@ use typst::geom::Transform;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Move
|
||||
/// Move content without affecting layout.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to move.
|
||||
///
|
||||
@ -14,8 +15,8 @@ use crate::prelude::*;
|
||||
/// - dy: Rel<Length> (named)
|
||||
/// The vertical displacement of the content.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -58,64 +59,44 @@ impl Layout for MoveNode {
|
||||
|
||||
impl Inline for MoveNode {}
|
||||
|
||||
/// Transform content without affecting layout.
|
||||
/// # Rotate
|
||||
/// Rotate content with affecting layout.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to transform.
|
||||
/// The content to rotate.
|
||||
///
|
||||
/// - angle: Angle (named)
|
||||
/// The amount of rotation.
|
||||
///
|
||||
/// - x: Ratio (named)
|
||||
/// The horizontal scaling factor.
|
||||
///
|
||||
/// - y: Ratio (named)
|
||||
/// The vertical scaling factor.
|
||||
///
|
||||
/// # Tags
|
||||
/// - layout
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct TransformNode<const T: TransformKind> {
|
||||
/// Transformation to apply to the content.
|
||||
pub transform: Transform,
|
||||
/// The content that should be transformed.
|
||||
pub struct RotateNode {
|
||||
/// The angle by which to rotate the node.
|
||||
pub angle: Angle,
|
||||
/// The content that should be rotated.
|
||||
pub body: Content,
|
||||
}
|
||||
|
||||
/// Rotate content without affecting layout.
|
||||
pub type RotateNode = TransformNode<ROTATE>;
|
||||
|
||||
/// Scale content without affecting layout.
|
||||
pub type ScaleNode = TransformNode<SCALE>;
|
||||
|
||||
#[node]
|
||||
impl<const T: TransformKind> TransformNode<T> {
|
||||
/// The origin of the transformation.
|
||||
impl RotateNode {
|
||||
/// The origin of the rotation.
|
||||
#[property(resolve)]
|
||||
pub const ORIGIN: Axes<Option<GenAlign>> = Axes::default();
|
||||
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
let transform = match T {
|
||||
ROTATE => {
|
||||
let angle = args.named_or_find("angle")?.unwrap_or_default();
|
||||
Transform::rotate(angle)
|
||||
Ok(Self {
|
||||
angle: args.named_or_find("angle")?.unwrap_or_default(),
|
||||
body: args.expect("body")?,
|
||||
}
|
||||
SCALE | _ => {
|
||||
let all = args.find()?;
|
||||
let sx = args.named("x")?.or(all).unwrap_or(Ratio::one());
|
||||
let sy = args.named("y")?.or(all).unwrap_or(Ratio::one());
|
||||
Transform::scale(sx, sy)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { transform, body: args.expect("body")? }.pack())
|
||||
.pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const T: TransformKind> Layout for TransformNode<T> {
|
||||
impl Layout for RotateNode {
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
@ -127,7 +108,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
|
||||
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
|
||||
let Axes { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
|
||||
let transform = Transform::translate(x, y)
|
||||
.pre_concat(self.transform)
|
||||
.pre_concat(Transform::rotate(self.angle))
|
||||
.pre_concat(Transform::translate(-x, -y));
|
||||
frame.transform(transform);
|
||||
}
|
||||
@ -135,15 +116,69 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const T: TransformKind> Inline for TransformNode<T> {}
|
||||
impl Inline for RotateNode {}
|
||||
|
||||
/// Kinds of transformations.
|
||||
/// # Scale
|
||||
/// Scale content without affecting layout.
|
||||
///
|
||||
/// The move transformation is handled separately.
|
||||
pub type TransformKind = usize;
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to scale.
|
||||
///
|
||||
/// - x: Ratio (named)
|
||||
/// The horizontal scaling factor.
|
||||
///
|
||||
/// - y: Ratio (named)
|
||||
/// The vertical scaling factor.
|
||||
///
|
||||
/// ## Category
|
||||
/// layout
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct ScaleNode {
|
||||
/// Scaling factor.
|
||||
pub factor: Axes<Ratio>,
|
||||
/// The content that should be scaled.
|
||||
pub body: Content,
|
||||
}
|
||||
|
||||
/// A rotational transformation.
|
||||
const ROTATE: TransformKind = 1;
|
||||
#[node]
|
||||
impl ScaleNode {
|
||||
/// The origin of the transformation.
|
||||
#[property(resolve)]
|
||||
pub const ORIGIN: Axes<Option<GenAlign>> = Axes::default();
|
||||
|
||||
/// A scale transformation.
|
||||
const SCALE: TransformKind = 2;
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
let all = args.find()?;
|
||||
let x = args.named("x")?.or(all).unwrap_or(Ratio::one());
|
||||
let y = args.named("y")?.or(all).unwrap_or(Ratio::one());
|
||||
Ok(Self {
|
||||
factor: Axes::new(x, y),
|
||||
body: args.expect("body")?,
|
||||
}
|
||||
.pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Layout for ScaleNode {
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
styles: StyleChain,
|
||||
regions: Regions,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut fragment = self.body.layout(vt, styles, regions)?;
|
||||
for frame in &mut fragment {
|
||||
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
|
||||
let Axes { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
|
||||
let transform = Transform::translate(x, y)
|
||||
.pre_concat(Transform::scale(self.factor.x, self.factor.y))
|
||||
.pre_concat(Transform::translate(-x, -y));
|
||||
frame.transform(transform);
|
||||
}
|
||||
Ok(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
impl Inline for ScaleNode {}
|
||||
|
@ -196,7 +196,7 @@ fn items() -> LangItems {
|
||||
},
|
||||
link: |url| meta::LinkNode::from_url(url).pack(),
|
||||
ref_: |target| meta::RefNode(target).pack(),
|
||||
heading: |level, body| basics::HeadingNode { level, body }.pack(),
|
||||
heading: |level, body| basics::HeadingNode { level, title: body }.pack(),
|
||||
list_item: |body| basics::ListItem::List(Box::new(body)).pack(),
|
||||
enum_item: |number, body| basics::ListItem::Enum(number, Box::new(body)).pack(),
|
||||
desc_item: |term, body| {
|
||||
|
@ -1,13 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
/// # Vector
|
||||
/// A column vector.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - elements: Content (positional, variadic)
|
||||
/// The elements of the vector.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -59,24 +60,25 @@ pub enum Delimiter {
|
||||
|
||||
castable! {
|
||||
Delimiter,
|
||||
/// Delimit matrices with parentheses.
|
||||
/// Delimit vector with parentheses.
|
||||
"(" => Self::Paren,
|
||||
/// Delimit matrices with brackets.
|
||||
/// Delimit vector with brackets.
|
||||
"[" => Self::Bracket,
|
||||
/// Delimit matrices with curly braces.
|
||||
/// Delimit vector with curly braces.
|
||||
"{" => Self::Brace,
|
||||
/// Delimit matrices with vertical bars.
|
||||
/// Delimit vector with vertical bars.
|
||||
"|" => Self::Bar,
|
||||
}
|
||||
|
||||
/// # Cases
|
||||
/// A case distinction.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - branches: Content (positional, variadic)
|
||||
/// The branches of the case distinction.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -14,17 +14,18 @@ use self::tex::layout_tex;
|
||||
use crate::prelude::*;
|
||||
use crate::text::{FontFamily, LinebreakNode, SpaceNode, SymbolNode, TextNode};
|
||||
|
||||
/// # Math
|
||||
/// A piece of a mathematical formula.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - items: Content (positional, variadic)
|
||||
/// The individual parts of the formula.
|
||||
///
|
||||
/// - block: bool (named)
|
||||
/// Whether the formula is displayed as a separate block.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Show, Layout, Inline, Texify)]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
@ -259,14 +260,15 @@ impl Texify for Content {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Atom
|
||||
/// An atom in a math formula: `x`, `+`, `12`.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - text: EcoString (positional, required)
|
||||
/// The atom's text.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -305,17 +307,18 @@ impl Texify for AtomNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Accent
|
||||
/// An accented node.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - base: Content (positional, required)
|
||||
/// The base to which the accent is applied.
|
||||
///
|
||||
/// - accent: Content (positional, required)
|
||||
/// The accent to apply to the base.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -390,17 +393,18 @@ impl Texify for AccNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Fraction
|
||||
/// A fraction.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - num: Content (positional, required)
|
||||
/// The fraction's numerator.
|
||||
///
|
||||
/// - denom: Content (positional, required)
|
||||
/// The fraction's denominator.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -431,17 +435,18 @@ impl Texify for FracNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Binomial
|
||||
/// A binomial.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - upper: Content (positional, required)
|
||||
/// The binomial's upper index.
|
||||
///
|
||||
/// - lower: Content (positional, required)
|
||||
/// The binomial's lower index.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -472,9 +477,10 @@ impl Texify for BinomNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Script
|
||||
/// A sub- and/or superscript.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - base: Content (positional, required)
|
||||
/// The base to which the applies the sub- and/or superscript.
|
||||
///
|
||||
@ -484,8 +490,8 @@ impl Texify for BinomNode {
|
||||
/// - sup: Content (named)
|
||||
/// The superscript.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -528,14 +534,15 @@ impl Texify for ScriptNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Alignment Point
|
||||
/// A math alignment point: `&`, `&&`.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - index: usize (positional, required)
|
||||
/// The alignment point's index.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -554,14 +561,15 @@ impl Texify for AlignPointNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Square Root
|
||||
/// A square root.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The expression to take the square root of.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -583,14 +591,15 @@ impl Texify for SqrtNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Floor
|
||||
/// A floored expression.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The expression to floor.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -612,14 +621,15 @@ impl Texify for FloorNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Ceil
|
||||
/// A ceiled expression.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The expression to ceil.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,13 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
/// # Serif
|
||||
/// Serif (roman) font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -29,14 +30,15 @@ impl Texify for SerifNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Sans-serif
|
||||
/// Sans-serif font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -58,14 +60,15 @@ impl Texify for SansNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Bold
|
||||
/// Bold font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -87,14 +90,15 @@ impl Texify for BoldNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Italic
|
||||
/// Italic font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -116,14 +120,15 @@ impl Texify for ItalNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Calligraphic
|
||||
/// Calligraphic font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -145,14 +150,15 @@ impl Texify for CalNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Fraktur
|
||||
/// Fraktur font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -174,14 +180,15 @@ impl Texify for FrakNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Monospace
|
||||
/// Monospace font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -203,14 +210,15 @@ impl Texify for MonoNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Doublestruck
|
||||
/// Blackboard bold (double-struck) font style.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The piece of formula to style.
|
||||
///
|
||||
/// # Tags
|
||||
/// - math
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::layout::{LayoutRoot, PageNode};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Document
|
||||
/// The root element of a document and its metadata.
|
||||
///
|
||||
/// All documents are automatically wrapped in a `document` element. The main
|
||||
@ -10,8 +11,8 @@ use crate::prelude::*;
|
||||
/// The metadata set with this function is not rendered within the document.
|
||||
/// Instead, it is embedded in the compiled PDF file.
|
||||
///
|
||||
/// # Tags
|
||||
/// - meta
|
||||
/// ## Category
|
||||
/// meta
|
||||
#[func]
|
||||
#[capable(LayoutRoot)]
|
||||
#[derive(Hash)]
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crate::prelude::*;
|
||||
use crate::text::TextNode;
|
||||
|
||||
/// # Link
|
||||
/// Link to a URL or another location in the document.
|
||||
///
|
||||
/// The link function makes its positional `body` argument clickable and links
|
||||
/// it to the destination specified by the `dest` argument.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #show link: underline
|
||||
///
|
||||
@ -16,7 +17,7 @@ use crate::text::TextNode;
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - dest: Destination (positional, required)
|
||||
/// The destination the link points to.
|
||||
///
|
||||
@ -30,7 +31,7 @@ use crate::text::TextNode;
|
||||
/// coordinates of type `length`. Pages are counted from one, and the
|
||||
/// coordinates are relative to the page's top left corner.
|
||||
///
|
||||
/// # Example
|
||||
/// ### Example
|
||||
/// ```
|
||||
/// #link("mailto:hello@typst.app") \
|
||||
/// #link((page: 1, x: 0pt, y: 0pt))[
|
||||
@ -43,8 +44,8 @@ use crate::text::TextNode;
|
||||
/// 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.
|
||||
///
|
||||
/// # Tags
|
||||
/// - meta
|
||||
/// ## Category
|
||||
/// meta
|
||||
#[func]
|
||||
#[capable(Show, Finalize)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -3,13 +3,14 @@ use crate::layout::{BlockNode, HNode, HideNode, RepeatNode, Spacing};
|
||||
use crate::prelude::*;
|
||||
use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
||||
|
||||
/// Generate a section outline / table of contents.
|
||||
/// # Outline
|
||||
/// A section outline / table of contents.
|
||||
///
|
||||
/// This function generates a list of all headings in the
|
||||
/// document, up to a given depth. The [@heading] numbering will be reproduced
|
||||
/// within the outline.
|
||||
/// This function generates a list of all headings in the document, up to a
|
||||
/// given depth. The [heading](@heading) numbering will be reproduced within the
|
||||
/// outline.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// #outline()
|
||||
///
|
||||
@ -20,8 +21,8 @@ use crate::text::{LinebreakNode, SpaceNode, TextNode};
|
||||
/// #lorem(10)
|
||||
/// ```
|
||||
///
|
||||
/// # Tags
|
||||
/// - meta
|
||||
/// ## Category
|
||||
/// meta
|
||||
#[func]
|
||||
#[capable(Prepare, Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -31,8 +32,8 @@ pub struct OutlineNode;
|
||||
impl OutlineNode {
|
||||
/// The title of the outline.
|
||||
///
|
||||
/// - When set to `{auto}`, an appropriate title for the [@text] language will
|
||||
/// be used. This is the default.
|
||||
/// - When set to `{auto}`, an appropriate title for the [text](@text)
|
||||
/// language will be used. This is the default.
|
||||
/// - When set to `{none}`, the outline will not have a title.
|
||||
/// - A custom title can be set by passing content.
|
||||
#[property(referenced)]
|
||||
@ -44,7 +45,7 @@ impl OutlineNode {
|
||||
|
||||
/// Whether to indent the subheadings to align the start of their numbering
|
||||
/// with the title of their parents. This will only have an effect if a
|
||||
/// [@heading] numbering is set.
|
||||
/// [heading](@heading) numbering is set.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
@ -114,7 +115,7 @@ impl Show for OutlineNode {
|
||||
});
|
||||
|
||||
seq.push(
|
||||
HeadingNode { body, level: NonZeroUsize::new(1).unwrap() }
|
||||
HeadingNode { title: body, level: NonZeroUsize::new(1).unwrap() }
|
||||
.pack()
|
||||
.styled(HeadingNode::NUMBERING, None)
|
||||
.styled(HeadingNode::OUTLINED, false),
|
||||
@ -175,7 +176,7 @@ impl Show for OutlineNode {
|
||||
};
|
||||
|
||||
// Add the numbering and section name.
|
||||
let start = numbering + heading.body.clone();
|
||||
let start = numbering + heading.title.clone();
|
||||
seq.push(start.linked(Destination::Internal(loc)));
|
||||
|
||||
// Add filler symbols between the section name and page number.
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use crate::text::TextNode;
|
||||
|
||||
/// # Reference
|
||||
/// A reference to a label.
|
||||
///
|
||||
/// *Note: This function is currently unimplemented.*
|
||||
@ -10,17 +11,17 @@ use crate::text::TextNode;
|
||||
/// 1" for a reference to the first heading's label. The references are also
|
||||
/// links to the respective labels.
|
||||
///
|
||||
/// # Syntax
|
||||
/// ## Syntax
|
||||
/// This function also has dedicated syntax: A reference to a label can be
|
||||
/// created by typing an `@` followed by the name of the label (e.g. `[=
|
||||
/// Introduction <intro>]` can be referenced by typing `[@intro]`).
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - target: Label (positional, required)
|
||||
/// The label that should be referenced.
|
||||
///
|
||||
/// # Tags
|
||||
/// - meta
|
||||
/// ## Category
|
||||
/// meta
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -4,14 +4,15 @@ use ttf_parser::{GlyphId, OutlineBuilder};
|
||||
use super::TextNode;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Underline
|
||||
/// Typeset underline, stricken-through or overlined text.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to decorate.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,10 +1,11 @@
|
||||
use super::TextNode;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Space
|
||||
/// A text space.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Unlabellable, Behave)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -25,14 +26,15 @@ impl Behave for SpaceNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Line Break
|
||||
/// A line break.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - justify: bool (named)
|
||||
/// Whether to justify the line before the break.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Behave)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -54,14 +56,15 @@ impl Behave for LinebreakNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Strong Emphasis
|
||||
/// Strongly emphasizes content by increasing the font weight.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to strongly emphasize.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -107,14 +110,15 @@ impl Fold for Delta {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Emphasis
|
||||
/// Emphasizes content by flipping the italicness.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The content to emphasize.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
@ -152,27 +156,29 @@ impl Fold for Toggle {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Lowercase
|
||||
/// Convert text or content to lowercase.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - text: ToCase (positional, required)
|
||||
/// The text to convert to lowercase.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
pub fn lower(args: &mut Args) -> SourceResult<Value> {
|
||||
case(Case::Lower, args)
|
||||
}
|
||||
|
||||
/// # Uppercase
|
||||
/// Convert text or content to uppercase.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - text: ToCase (positional, required)
|
||||
/// The text to convert to uppercase.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
pub fn upper(args: &mut Args) -> SourceResult<Value> {
|
||||
case(Case::Upper, args)
|
||||
@ -216,14 +222,15 @@ impl Case {
|
||||
}
|
||||
}
|
||||
|
||||
/// # Small Capitals
|
||||
/// Display text in small capitals.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - text: Content (positional, required)
|
||||
/// The text to display to small capitals.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
pub fn smallcaps(args: &mut Args) -> SourceResult<Value> {
|
||||
let body: Content = args.expect("content")?;
|
||||
|
@ -25,17 +25,18 @@ use typst::util::EcoString;
|
||||
use crate::layout::ParNode;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Text
|
||||
/// Stylable text.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## 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.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Clone, Hash)]
|
||||
|
@ -2,14 +2,15 @@ use typst::syntax::is_newline;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Smart Quote
|
||||
/// A smart quote.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - double: bool (named)
|
||||
/// Whether to produce a smart double quote.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -6,17 +6,18 @@ use super::{FontFamily, Hyphenate, LinebreakNode, TextNode};
|
||||
use crate::layout::BlockNode;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Raw Text
|
||||
/// Raw text with optional syntax highlighting.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - text: EcoString (positional, required)
|
||||
/// The raw text.
|
||||
///
|
||||
/// - block: bool (named)
|
||||
/// Whether the raw text is displayed as a separate block.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -4,6 +4,7 @@ use typst::util::EcoString;
|
||||
use super::{variant, SpaceNode, TextNode, TextSize};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Subscript
|
||||
/// Sub- or superscript text.
|
||||
///
|
||||
/// The text is rendered smaller and its baseline is raised/lowered. To provide
|
||||
@ -11,12 +12,12 @@ use crate::prelude::*;
|
||||
/// superscript codepoints. If that fails, we fall back to rendering shrunk
|
||||
/// normal letters in a raised way.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional, required)
|
||||
/// The text to display in sub- or superscript.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,14 +1,15 @@
|
||||
use crate::prelude::*;
|
||||
use crate::text::TextNode;
|
||||
|
||||
/// # Symbol
|
||||
/// A symbol identified by symmie notation.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - notation: EcoString (positional, required)
|
||||
/// The symbols symmie notation.
|
||||
///
|
||||
/// # Tags
|
||||
/// - text
|
||||
/// ## Category
|
||||
/// text
|
||||
#[func]
|
||||
#[capable(Show)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -4,16 +4,17 @@ use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Image
|
||||
/// Show a raster or vector graphic.
|
||||
///
|
||||
/// Supported formats are PNG, JPEG, GIF and SVG.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - path: EcoString (positional, required)
|
||||
/// Path to an image file.
|
||||
///
|
||||
/// # Tags
|
||||
/// - visualize
|
||||
/// ## Category
|
||||
/// visualize
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Line
|
||||
/// Display a line without affecting the layout.
|
||||
///
|
||||
/// You should only provide either an endpoint or an angle and a length.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - origin: Axes<Rel<Length>> (named)
|
||||
/// The start point of the line.
|
||||
///
|
||||
@ -17,8 +18,8 @@ use crate::prelude::*;
|
||||
/// - angle: Angle (named)
|
||||
/// The angle at which the line points away from the origin.
|
||||
///
|
||||
/// # Tags
|
||||
/// - visualize
|
||||
/// ## Category
|
||||
/// visualize
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -2,9 +2,10 @@ use std::f64::consts::SQRT_2;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// # Rectangle
|
||||
/// A sizable and fillable shape with optional content.
|
||||
///
|
||||
/// # Parameters
|
||||
/// ## Parameters
|
||||
/// - body: Content (positional)
|
||||
/// The content to place into the shape.
|
||||
///
|
||||
@ -23,8 +24,8 @@ use crate::prelude::*;
|
||||
/// - stroke: Smart<Sides<Option<PartialStroke>>> (named)
|
||||
/// How to stroke the shape.
|
||||
///
|
||||
/// # Tags
|
||||
/// - visualize
|
||||
/// ## Category
|
||||
/// visualize
|
||||
#[func]
|
||||
#[capable(Layout, Inline)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
@ -4,27 +4,34 @@ use super::*;
|
||||
|
||||
/// Expand the `#[func]` macro.
|
||||
pub fn func(item: syn::Item) -> Result<TokenStream> {
|
||||
let mut docs = match &item {
|
||||
let docs = match &item {
|
||||
syn::Item::Struct(item) => documentation(&item.attrs),
|
||||
syn::Item::Enum(item) => documentation(&item.attrs),
|
||||
syn::Item::Fn(item) => documentation(&item.attrs),
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
let tags = tags(&mut docs);
|
||||
let first = docs.lines().next().unwrap();
|
||||
let display = first.strip_prefix("# ").unwrap();
|
||||
let display = display.trim();
|
||||
|
||||
let mut docs = docs[first.len()..].to_string();
|
||||
let example = example(&mut docs, 2);
|
||||
let params = params(&mut docs)?;
|
||||
let example = quote_option(example(&mut docs));
|
||||
let syntax = quote_option(section(&mut docs, "Syntax"));
|
||||
let syntax = quote_option(section(&mut docs, "Syntax", 2));
|
||||
let category = section(&mut docs, "Category", 2).expect("missing category");
|
||||
let example = quote_option(example);
|
||||
|
||||
let docs = docs.trim();
|
||||
if docs.contains("# ") {
|
||||
bail!(item, "Documentation heading not recognized");
|
||||
bail!(item, "unrecognized heading");
|
||||
}
|
||||
|
||||
let info = quote! {
|
||||
::typst::model::FuncInfo {
|
||||
name,
|
||||
tags: &[#(#tags),*],
|
||||
display: #display,
|
||||
category: #category,
|
||||
docs: #docs,
|
||||
example: #example,
|
||||
syntax: #syntax,
|
||||
@ -57,7 +64,7 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
|
||||
|
||||
impl::typst::model::FuncType for #ty {
|
||||
fn create_func(name: &'static str) -> ::typst::model::Func {
|
||||
::typst::model::Func::from_fn(name, #full, #info)
|
||||
::typst::model::Func::from_fn(#full, #info)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -75,7 +82,7 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
|
||||
|
||||
impl #params ::typst::model::FuncType for #ident #args #clause {
|
||||
fn create_func(name: &'static str) -> ::typst::model::Func {
|
||||
::typst::model::Func::from_node::<Self>(name, #info)
|
||||
::typst::model::Func::from_node::<Self>(#info)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -83,31 +90,27 @@ pub fn func(item: syn::Item) -> Result<TokenStream> {
|
||||
}
|
||||
|
||||
/// Extract a section.
|
||||
pub fn section(docs: &mut String, title: &str) -> Option<String> {
|
||||
let needle = format!("\n# {title}\n");
|
||||
pub fn section(docs: &mut String, title: &str, level: usize) -> Option<String> {
|
||||
let hashtags = "#".repeat(level);
|
||||
let needle = format!("\n{hashtags} {title}\n");
|
||||
let start = docs.find(&needle)?;
|
||||
let rest = &docs[start..];
|
||||
let len = rest[1..].find("\n# ").map(|x| 1 + x).unwrap_or(rest.len());
|
||||
let len = rest[1..]
|
||||
.find("\n# ")
|
||||
.or(rest[1..].find("\n## "))
|
||||
.or(rest[1..].find("\n### "))
|
||||
.map(|x| 1 + x)
|
||||
.unwrap_or(rest.len());
|
||||
let end = start + len;
|
||||
let section = docs[start + needle.len()..end].trim().to_owned();
|
||||
docs.replace_range(start..end, "");
|
||||
Some(section)
|
||||
}
|
||||
|
||||
/// Parse the tag section.
|
||||
fn tags(docs: &mut String) -> Vec<String> {
|
||||
section(docs, "Tags")
|
||||
.unwrap_or_default()
|
||||
.lines()
|
||||
.filter_map(|line| line.strip_prefix('-'))
|
||||
.map(|s| s.trim().into())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Parse the example section.
|
||||
pub fn example(docs: &mut String) -> Option<String> {
|
||||
pub fn example(docs: &mut String, level: usize) -> Option<String> {
|
||||
Some(
|
||||
section(docs, "Example")?
|
||||
section(docs, "Example", level)?
|
||||
.lines()
|
||||
.skip_while(|line| !line.contains("```"))
|
||||
.skip(1)
|
||||
@ -119,7 +122,7 @@ pub fn example(docs: &mut String) -> Option<String> {
|
||||
|
||||
/// Parse the parameter section.
|
||||
fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
|
||||
let Some(section) = section(docs, "Parameters") else { return Ok(vec![]) };
|
||||
let Some(section) = section(docs, "Parameters", 2) else { return Ok(vec![]) };
|
||||
let mut s = Scanner::new(§ion);
|
||||
let mut infos = vec![];
|
||||
|
||||
@ -159,7 +162,7 @@ fn params(docs: &mut String) -> Result<Vec<TokenStream>> {
|
||||
s.expect(')');
|
||||
|
||||
let mut docs = dedent(s.eat_until("\n-").trim());
|
||||
let example = quote_option(example(&mut docs));
|
||||
let example = quote_option(example(&mut docs, 3));
|
||||
let docs = docs.trim();
|
||||
|
||||
infos.push(quote! {
|
||||
|
@ -337,7 +337,7 @@ fn create_node_properties_func(node: &Node) -> syn::ImplItemMethod {
|
||||
let shorthand = matches!(property.shorthand, Some(Shorthand::Positional));
|
||||
|
||||
let mut docs = documentation(&property.attrs);
|
||||
let example = quote_option(super::func::example(&mut docs));
|
||||
let example = quote_option(super::func::example(&mut docs, 1));
|
||||
let docs = docs.trim();
|
||||
|
||||
quote! {
|
||||
|
@ -42,6 +42,11 @@ impl Em {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// The absolute value of this em length.
|
||||
pub fn abs(self) -> Self {
|
||||
Self::new(self.get().abs())
|
||||
}
|
||||
|
||||
/// Convert to an absolute length at the given font size.
|
||||
pub fn at(self, font_size: Abs) -> Abs {
|
||||
let resolved = font_size * self.get();
|
||||
|
@ -18,6 +18,12 @@ impl Length {
|
||||
Self { abs: Abs::zero(), em: Em::zero() }
|
||||
}
|
||||
|
||||
/// Try to compute the absolute value of the length.
|
||||
pub fn try_abs(self) -> Option<Self> {
|
||||
(self.abs.is_zero() || self.em.is_zero())
|
||||
.then(|| Self { abs: self.abs.abs(), em: self.em.abs() })
|
||||
}
|
||||
|
||||
/// Try to divide two lengths.
|
||||
pub fn try_div(self, other: Self) -> Option<f64> {
|
||||
if self.abs.is_zero() && other.abs.is_zero() {
|
||||
|
@ -774,7 +774,7 @@ impl<'a> CompletionContext<'a> {
|
||||
matches!(
|
||||
value,
|
||||
Value::Func(func) if func.info().map_or(false, |info| {
|
||||
info.tags.contains(&"math")
|
||||
info.category == "math"
|
||||
}),
|
||||
)
|
||||
});
|
||||
@ -805,7 +805,7 @@ impl<'a> CompletionContext<'a> {
|
||||
!short_form || matches!(
|
||||
value,
|
||||
Value::Func(func) if func.info().map_or(true, |info| {
|
||||
!info.tags.contains(&"math")
|
||||
info.category != "math"
|
||||
}),
|
||||
)
|
||||
});
|
||||
|
@ -476,10 +476,7 @@ impl Eval for ast::Frac {
|
||||
type Output = Content;
|
||||
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.math_frac)(
|
||||
self.num().eval(vm)?,
|
||||
self.denom().eval(vm)?,
|
||||
))
|
||||
Ok((vm.items.math_frac)(self.num().eval(vm)?, self.denom().eval(vm)?))
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,11 +778,7 @@ impl Eval for ast::FieldAccess {
|
||||
.field(&field)
|
||||
.ok_or_else(|| format!("unknown field {field:?}"))
|
||||
.at(span)?,
|
||||
v => bail!(
|
||||
self.target().span(),
|
||||
"cannot access field on {}",
|
||||
v.type_name()
|
||||
),
|
||||
v => bail!(self.target().span(), "cannot access field on {}", v.type_name()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -37,18 +37,16 @@ impl Func {
|
||||
|
||||
/// Create a new function from a native rust function.
|
||||
pub fn from_fn(
|
||||
name: &'static str,
|
||||
func: fn(&Vm, &mut Args) -> SourceResult<Value>,
|
||||
info: FuncInfo,
|
||||
) -> Self {
|
||||
Self(Arc::new(Repr::Native(Native { name, func, set: None, node: None, info })))
|
||||
Self(Arc::new(Repr::Native(Native { func, set: None, node: None, info })))
|
||||
}
|
||||
|
||||
/// Create a new function from a native rust node.
|
||||
pub fn from_node<T: Node>(name: &'static str, mut info: FuncInfo) -> Self {
|
||||
pub fn from_node<T: Node>(mut info: FuncInfo) -> Self {
|
||||
info.params.extend(T::properties());
|
||||
Self(Arc::new(Repr::Native(Native {
|
||||
name,
|
||||
func: |ctx, args| {
|
||||
let styles = T::set(args, true)?;
|
||||
let content = T::construct(ctx, args)?;
|
||||
@ -68,7 +66,7 @@ impl Func {
|
||||
/// The name of the function.
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
match self.0.as_ref() {
|
||||
Repr::Native(native) => Some(native.name),
|
||||
Repr::Native(native) => Some(native.info.name),
|
||||
Repr::Closure(closure) => closure.name.as_deref(),
|
||||
Repr::With(func, _) => func.name(),
|
||||
}
|
||||
@ -184,8 +182,6 @@ pub trait FuncType {
|
||||
|
||||
/// A function defined by a native rust function or node.
|
||||
struct Native {
|
||||
/// The name of the function.
|
||||
name: &'static str,
|
||||
/// The function pointer.
|
||||
func: fn(&Vm, &mut Args) -> SourceResult<Value>,
|
||||
/// The set rule.
|
||||
@ -198,7 +194,6 @@ struct Native {
|
||||
|
||||
impl Hash for Native {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state);
|
||||
(self.func as usize).hash(state);
|
||||
self.set.map(|set| set as usize).hash(state);
|
||||
self.node.hash(state);
|
||||
@ -210,8 +205,10 @@ impl Hash for Native {
|
||||
pub struct FuncInfo {
|
||||
/// The function's name.
|
||||
pub name: &'static str,
|
||||
/// Tags that categorize the function.
|
||||
pub tags: &'static [&'static str],
|
||||
/// The display name of the function.
|
||||
pub display: &'static str,
|
||||
/// Which category the function is part of.
|
||||
pub category: &'static str,
|
||||
/// Documentation for the function.
|
||||
pub docs: &'static str,
|
||||
/// The source code of an example, if any.
|
||||
|
@ -145,6 +145,9 @@ impl Args {
|
||||
}
|
||||
|
||||
fn library() -> Library {
|
||||
/// # Test
|
||||
/// ## Category
|
||||
/// test
|
||||
#[func]
|
||||
fn test(args: &mut typst::model::Args) -> SourceResult<Value> {
|
||||
let lhs = args.expect::<Value>("left-hand side")?;
|
||||
@ -155,6 +158,9 @@ fn library() -> Library {
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
||||
/// # Print
|
||||
/// ## Category
|
||||
/// test
|
||||
#[func]
|
||||
fn print(args: &mut typst::model::Args) -> SourceResult<Value> {
|
||||
print!("> ");
|
||||
|
Loading…
x
Reference in New Issue
Block a user