9.8 KiB
description |
---|
Automate your document with Typst's scripting capabilities. |
Scripting
Typst embeds a powerful scripting language. You can automate your documents and create more sophisticated styles with code. Below is an overview over the scripting concepts.
Expressions
In Typst, markup and code are fused into one. All but the most common elements
are created with functions. To make this as convenient as possible, Typst
provides compact syntax to embed a code expression into markup: An expression is
introduced with a hashtag (#
) and normal markup parsing resumes after the
expression is finished. If a character would continue the expression but should
be interpreted as text, the expression can forcibly be ended with a semicolon
(;
).
#rect[Hello] \
#emoji.face \
#"hello".len()
The example above shows a few of the available expressions, including
function calls,
field accesses, and
method calls. More kinds of expressions are
discussed in the remainder of this chapter. A few kinds of expressions are not
compatible with the hashtag syntax (e.g. binary operator expressions). To embed
these into markup, you can use parentheses, as in [#(1 + 2)]
.
Blocks
To structure your code and embed markup into it, Typst provides two kinds of blocks:
-
Code block:
{{ let x = 1; x + 2 }}
When writing code, you'll probably want to split up your computation into multiple statements, create some intermediate variables and so on. Code blocks let you write multiple expressions where one is expected. The individual expressions in a code block should be separated by line breaks or semicolons. The output values of the individual expressions in a code block are joined to determine the block's value. Expressions without useful output, like{let}
bindings yield{none}
, which can be joined with any value without effect. -
Content block:
{[*Hey* there!]}
With content blocks, you can handle markup/content as a programmatic value, store it in variables and pass it to functions. Content blocks are delimited by square brackets and can contain arbitrary markup. A content block results in a value of type content. An arbitrary number of content blocks can be passed as trailing arguments to functions. That is,{list([A], [B])}
is equivalent to{list[A][B]}
.
Content and code blocks can be nested arbitrarily. In the example below,
{[hello]}
is joined with the output of {a + [ the ] + b}
yielding
{[hello from the *world*]}
.
#{
let a = [from]
let b = [*world*]
[hello ]
a + [ the ] + b
}
Let bindings
As already demonstrated above, variables can be defined with {let}
bindings.
The variable is assigned the value of the expression that follows the =
sign.
The assignment of a value is optional, if no value is assigned, the variable
will be initialized as {none}
. The {let}
keyword can also be used to create
a custom named function. Let bindings can be
accessed for the rest of the containing block or document.
#let name = "Typst"
This is #name's documentation.
It explains #name.
#let add(x, y) = x + y
Sum is #add(2, 3).
Conditionals
With a conditional, you can display or compute different things depending on
whether some condition is fulfilled. Typst supports {if}
, {else if}
and
{else}
expression. When the condition evaluates to {true}
, the conditional
yields the value resulting from the if's body, otherwise yields the value
resulting from the else's body.
#if 1 < 2 [
This is shown
] else [
This is not.
]
Each branch can have a code or content block as its body.
{if condition {..}}
{if condition [..]}
{if condition [..] else {..}}
{if condition [..] else if condition {..} else [..]}
Loops
With loops, you can repeat content or compute something iteratively. Typst
supports two types of loops: {for}
and {while}
loops. The former iterate
over a specified collection whereas the latter iterate as long as a condition
stays fulfilled. Just like blocks, loops join the results from each iteration
into one value.
In the example below, the three sentences created by the for loop join together into a single content value and the length-1 arrays in the while loop join together into one larger array.
#for c in "ABC" [
#c is a letter.
]
#let n = 2
#while n < 10 {
n = (n * 2) - 1
(n,)
}
For loops can iterate over a variety of collections:
-
{for letter in "abc" {..}}
Iterates over the characters of the string. (Technically, iterates over the grapheme clusters of the string. Most of the time, a grapheme cluster is just a single character/codepoint. However, some constructs like flag emojis that consist of multiple codepoints are still only one cluster.) -
{for value in array {..}}
{for index, value in array {..}}
Iterates over the items in the array. Can also provide the index of each element. -
{for value in dict {..}}
{for key, value in dict {..}}
Iterates over the values or keys and values of the dictionary. -
{for value in args {..}}
{for name, value in args {..}}
Iterates over the values or names and values of the arguments. For positional arguments, thename
is{none}
.
To control the execution of the loop, Typst provides the {break}
and
{continue}
statements. The former performs an early exit from the loop while
the latter skips ahead to the next iteration of the loop.
#for letter in "abc nope" {
if letter == " " {
break
}
letter
}
The body of a loop can be a code or content block:
{for .. in collection {..}}
{for .. in collection [..]}
{while condition [..]}
{while condition [..]}
Fields
You can use dot notation to access fields on a value. The value in question can be either:
- a dictionary that has the specified key,
- a symbols that has the specified modifier,
- a module containing the specified definition,
- content that exposes the specified field. Most elements expose some or all of the non-settable arguments passed to them as fields.
#let dict = (greet: "Hello")
#dict.greet \
#emoji.face
Methods
A method is a kind of a function that is tightly coupled with
a specific type. It is called on a value of its type using the same dot notation
that is also used for fields: {value.method(..)}
. The
type documentation lists the available methods for each of the built-in
types. You cannot define your own methods.
#let array = (1, 2, 3, 4)
#array.pop() \
#array.len() \
#("a, b, c"
.split(", ")
.join[ --- ])
Methods are the only functions in Typst that can modify the value they are called on.
Modules
You can split up your Typst projects into multiple files called modules. A module can refer to the content and definitions of another module in multiple ways:
-
Including:
{include "bar.typ"}
Evaluates the file at the pathbar.typ
and returns the resulting content. -
Import:
{import "bar.typ"}
Evaluates the file at the pathbar.typ
and inserts the resulting module into the current scope asbar
(filename without extension). -
Import items:
{import "bar.typ": a, b}
Evaluates the file at the pathbar.typ
, extracts the values of the variablesa
andb
(that need to be defined inbar.typ
, e.g. through{let}
bindings) and defines them in the current file.Replacinga, b
with*
loads all variables defined in a module.
Instead of a path, you can also use a module value, as shown in the following example:
#import emoji: face
#face.grin
Operators
The following table lists all available unary and binary operators with effect, arity (unary, binary) and precedence level (higher binds stronger).
Operator | Effect | Arity | Precedence |
---|---|---|---|
{-} |
Negation | Unary | 7 |
{+} |
No effect (exists for symmetry) | Unary | 7 |
{*} |
Multiplication | Binary | 6 |
{/} |
Division | Binary | 6 |
{+} |
Addition | Binary | 5 |
{-} |
Subtraction | Binary | 5 |
{==} |
Check equality | Binary | 4 |
{!=} |
Check inequality | Binary | 4 |
{<} |
Check less-than | Binary | 4 |
{<=} |
Check less-than or equal | Binary | 4 |
{>} |
Check greater-than | Binary | 4 |
{>=} |
Check greater-than or equal | Binary | 4 |
{in} |
Check if in collection | Binary | 4 |
{not in} |
Check if not in collection | Binary | 4 |
{not} |
Logical "not" | Unary | 3 |
{and} |
Short-circuiting logical "and" | Binary | 3 |
{or} |
Short-circuiting logical "or | Binary | 2 |
{=} |
Assignment | Binary | 1 |
{+=} |
Add-Assignment | Binary | 1 |
{-=} |
Subtraction-Assignment | Binary | 1 |
{*=} |
Multiplication-Assignment | Binary | 1 |
{/=} |
Division-Assignment | Binary | 1 |