summaryrefslogtreecommitdiff
path: root/docs/reference/language/scripting.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/reference/language/scripting.md')
-rw-r--r--docs/reference/language/scripting.md373
1 files changed, 373 insertions, 0 deletions
diff --git a/docs/reference/language/scripting.md b/docs/reference/language/scripting.md
new file mode 100644
index 00000000..5e0f1555
--- /dev/null
+++ b/docs/reference/language/scripting.md
@@ -0,0 +1,373 @@
+---
+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 hash (`#`) 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
+(`;`).
+
+```example
+#emph[Hello] \
+#emoji.face \
+#"hello".len()
+```
+
+The example above shows a few of the available expressions, including
+[function calls]($function), [field accesses]($scripting/#fields), and
+[method calls]($scripting/#methods). More kinds of expressions are
+discussed in the remainder of this chapter. A few kinds of expressions are not
+compatible with the hash 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]($function). 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*]}`.
+
+```example
+#{
+ let a = [from]
+ let b = [*world*]
+ [hello ]
+ a + [ the ] + b
+}
+```
+
+## Bindings and Destructuring { #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]($function/#defining-functions). Variables can be
+accessed for the rest of the containing block (or the rest of the file if there
+is no containing block).
+
+```example
+#let name = "Typst"
+This is #name's documentation.
+It explains #name.
+
+#let add(x, y) = x + y
+Sum is #add(2, 3).
+```
+
+Let bindings can also be used to destructure [arrays]($array) and
+[dictionaries]($dictionary). In this case, the left-hand side of the
+assignment should mirror an array or dictionary. The `..` operator can be used
+once in the pattern to collect the remainder of the array's or dictionary's
+items.
+
+```example
+#let (x, y) = (1, 2)
+The coordinates are #x, #y.
+
+#let (a, .., b) = (1, 2, 3, 4)
+The first element is #a.
+The last element is #b.
+
+#let books = (
+ Shakespeare: "Hamlet",
+ Homer: "The Odyssey",
+ Austen: "Persuasion",
+)
+
+#let (Austen,) = books
+Austen wrote #Austen.
+
+#let (Homer: h) = books
+Homer wrote #h.
+
+#let (Homer, ..other) = books
+#for (author, title) in other [
+ #author wrote #title.
+]
+```
+
+You can use the underscore to discard elements in a destructuring pattern:
+
+```example
+#let (_, y, _) = (1, 2, 3)
+The y coordinate is #y.
+```
+
+Destructuring also works in argument lists of functions ...
+
+```example
+#let left = (2, 4, 5)
+#let right = (3, 2, 6)
+#left.zip(right).map(
+ ((a,b)) => a + b
+)
+```
+
+... and on the left-hand side of normal assignments. This can be useful to
+swap variables among other things.
+
+```example
+#{
+ let a = 1
+ let b = 2
+ (a, b) = (b, a)
+ [a = #a, b = #b]
+}
+```
+
+## 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}` expressions. 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.
+
+```example
+#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.
+
+```example
+#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 value in array {..}}` \
+ Iterates over the items in the [array]. The destructuring syntax described in
+ [Let binding]($scripting/#bindings) can also be used here.
+
+- `{for pair in dict {..}}` \
+ Iterates over the key-value pairs of the [dictionary]. The pairs can also be
+ destructured by using `{for (key, value) in dict {..}}`. It is more efficient
+ than `{for pair in dict.pairs() {..}}` because it doesn't create a temporary
+ array of all key-value pairs.
+
+- `{for letter in "abc" {..}}` \
+ Iterates over the characters of the [string]($str). Technically, it iterates
+ over the grapheme clusters of the string. Most of the time, a grapheme cluster
+ is just a single codepoint. However, a grapheme cluster could contain multiple
+ codepoints, like a flag emoji.
+
+- `{for byte in bytes("😀") {..}}` \
+ Iterates over the [bytes], which can be converted from a [string]($str) or
+ [read] from a file without encoding. Each byte value is an [integer]($int)
+ between `{0}` and `{255}`.
+
+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.
+
+```example
+#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. For values of type
+[`content`], you can also use the [`fields`]($content.fields) function to list
+the fields.
+
+The value in question can be either:
+- a [dictionary] that has the specified key,
+- a [symbol] that has the specified modifier,
+- a [module] containing the specified definition,
+- [content] consisting of an element that has the specified field. The
+ available fields match the arguments of the
+ [element function]($function/#element-functions) that were given when the
+ element was constructed.
+
+```example
+#let it = [= Heading]
+#it.body \
+#it.depth \
+#it.fields()
+
+#let dict = (greet: "Hello")
+#dict.greet \
+#emoji.face
+
+```
+
+## Methods
+A _method call_ is a convenient way to call a function that is scoped to a
+value's [type]. For example, we can call the [`str.len`]($str.len) function in
+the following two equivalent ways:
+
+```example
+#str.len("abc") is the same as
+#"abc".len()
+```
+
+The structure of a method call is `{value.method(..args)}` and its equivalent
+full function call is `{type(value).method(value, ..args)}`. The documentation
+of each type lists its scoped functions. You cannot currently define your own
+methods.
+
+```example
+#let values = (1, 2, 3, 4)
+#values.pop() \
+#values.len() \
+
+#("a, b, c"
+ .split(", ")
+ .join[ --- ])
+
+#"abc".len() is the same as
+#str.len("abc")
+```
+
+There are a few special functions that modify the value they are called on (e.g.
+[`array.push`]($array.push)). These functions _must_ be called in method form.
+In some cases, when the method is only called for its side effect, its return
+value should be ignored (and not participate in joining). The canonical way to
+discard a value is with a let binding: `{let _ = array.remove(1)}`.
+
+## 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 path `bar.typ` and returns the resulting [content].
+
+- **Import:** `{import "bar.typ"}` \
+ Evaluates the file at the path `bar.typ` and inserts the resulting [module]
+ into the current scope as `bar` (filename without extension). You can use the
+ `as` keyword to rename the imported module: `{import "bar.typ" as baz}`. You
+ can import nested items using dot notation: `{import "bar.typ": baz.a}`.
+
+- **Import items:** `{import "bar.typ": a, b}` \
+ Evaluates the file at the path `bar.typ`, extracts the values of the variables
+ `a` and `b` (that need to be defined in `bar.typ`, e.g. through `{let}`
+ bindings) and defines them in the current file. Replacing `a, b` with `*`
+ loads all variables defined in a module. You can use the `as` keyword to
+ rename the individual items: `{import "bar.typ": a as one, b as two}`
+
+Instead of a path, you can also use a [module value]($module), as shown in the
+following example:
+
+```example
+#import emoji: face
+#face.grin
+```
+
+## Packages
+To reuse building blocks across projects, you can also create and import Typst
+_packages._ A package import is specified as a triple of a namespace, a name,
+and a version.
+
+```example
+>>> #let add(x, y) = x + y
+<<< #import "@preview/example:0.1.0": add
+#add(2, 7)
+```
+
+The `preview` namespace contains packages shared by the community. You can find
+all available community packages on [Typst Universe]($universe).
+
+If you are using Typst locally, you can also create your own system-local
+packages. For more details on this, see the
+[package repository](https://github.com/typst/packages).
+
+## Operators
+The following table lists all available unary and binary operators with effect,
+arity (unary, binary) and precedence level (higher binds stronger). Some
+operations, such as [modulus]($calc.rem-euclid), do not have a special syntax
+and can be achieved using functions from the
+[`calc`]($category/foundations/calc) module.
+
+| 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 |
+
+[semver]: https://semver.org/