https://github.com/jneug/typst-tools4typst
An utility package for typst package authors.
https://github.com/jneug/typst-tools4typst
Last synced: 14 days ago
JSON representation
An utility package for typst package authors.
- Host: GitHub
- URL: https://github.com/jneug/typst-tools4typst
- Owner: jneug
- License: mit
- Created: 2023-07-29T19:37:24.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-09-14T21:18:17.000Z (over 1 year ago)
- Last Synced: 2024-08-02T06:17:35.992Z (9 months ago)
- Language: Typst
- Size: 1.35 MB
- Stars: 11
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-typst - typst-tools4typst - Tools for package and template authors. (Templates & Libraries / Scripting)
- jimsghstars - jneug/typst-tools4typst - An utility package for typst package authors. (Typst)
README
# Tools for Typst (v0.4.2)
> A utility package for typst package authors.
**Tools for Typst** (`t4t` in short) is a utility package for [Typst](typst/typst) package and template authors. It provides solutions to some recurring tasks in package development.
The package can be imported or any useful parts of it copied into a project. It is perfectly fine to treat `t4t` as a snippet collection and to pick and choose only some useful functions. For this reason, most functions are implemented without further dependencies.
Hopefully, this collection will grow over time with *Typst* to provide solutions for common problems.
## Usage
Either import the package from the Typst preview repository:
```typst
#import "@preview/t4t:0.4.2": *
```If only a few functions from `t4t` are needed, simply copy the necessary code to the beginning of the document.
## Reference
----
**Note:** This reference might be out of date. Please refer to the manual for a complete overview of all functions.
----
The functions are categorized into different submodules that can be imported separately.
The modules are:
- `is`
- `def`
- `assert`
- `alias`
- `math`
- `get`Any or all modules can be imported the usual way:
```typst
// Import as "t4t"
#import "@preview/t4t:0.4.2"
// Import all modules
#import "@preview/t4t:0.4.2": *
// Import specific modules
#import "@preview/t4t:0.4.2": is, def
```In general, the main value is passed last to the utility functions. `#def.if-none()`, for example, takes the default value first and the value to test second. This is somewhat counterintuitive at first, but allows the use of `.with()` to generate derivative functions:
```typst
#let is-foo = eq.with("foo")
```### Test functions
```typst
#import "@preview/t4t:0.4.2": *
#import "@preview/t4t:0.4.2": test
```These functions provide shortcuts to common tests like `#is-eq()`. Some of these are not shorter as writing pure Typst code (e.g. `a == b`), but can easily be used in `.any()` or `.find()` calls:
```typst
// check all values for none
if some-array.any(is-none) {
...
}// find first not none value
let x = (none, none, 5, none).find(not-none)// find position of a value
let pos-bar = args.pos().position(test.is-eq.with("|"))
```Some of the more frequently used tests are available as top-level imports from `t4t`. The rest can be found in the `test` module.
```typst
#import "@preview/t4t:0.4.2"#if t4t.is-none(none) [
it is none
]
```The following tests are available in the base `t4t` module:
- `#is-none( ..values )`: Tests if any of the passed `values` is `none`.
- `#not-none( ..values )`: Tests if all of the passed `values` are not `none`.
- `#is-auto( ..values )`: Tests if any of the passed `values` is `auto`.
- `#not-auto( ..values )`: Tests if all of the passed `values` are not `auto`.
- `#is-empty( value )`: Tests if `value` is _empty_. A value is considered _empty_ if it is an empty array, dictionary or string or `none` otherwise.
- `#not-empty( value )`: Tests if `value` is not empty.- `#is-dict( value )`: Tests if `value` is a dictionary.
- `#is-arr( value )`: Tests if `value` is an array.
- `#is-content( value )`: Tests if `value` is of type content.
- `#is-color( value )`: Tests if `value` is a color.
- `#is-stroke( value )`: Tests if `value` is a stroke.
- `#is-loc( value )`: Tests if `value` is a location.
- `#is-bool( value )`: Tests if `value` is a boolean.
- `#is-str( value )`: Tests if `value` is a string.
- `#is-int( value )`: Tests if `value` is an integer.
- `#is-float( value )`: Tests if `value` is a float.
- `#is-num( value )`: Tests if `value` is a numeric value (`integer` or `float`).
- `#is-frac( value )`: Tests if `value` is a fraction.
- `#is-length( value )`: Tests if `value` is a length.
- `#is-relative( value )`: Tests if `value` is a relative length.
- `#is-ratio( value )`: Tests if `value` is a ratio.
- `#is-align( value )`: Tests if `value` is an alignment.
- `#is-align2d( value )`: Tests if `value` is a 2d alignment.
- `#is-func( value )`: Tests if `value` is a function.- `#test.neg( test )`: Creates a new test function that is `true` when `test` is `false`. Can be used to create negations of tests like `#let not-raw = is.neg(is.raw)`.
- `#test.eq( a, b )`: Tests if values `a` and `b` are equal.
- `#test.neq( a, b )`: Tests if values `a` and `b` are not equal.
- `#test.any( ..compare, value )`: Tests if `value` is equal to any one of the other passed-in values.
- `#test.not-any( ..compare, value)`: Tests if `value` is not equal to any one of the other passed-in values.
- `#test.has( ..keys, value )`: Tests if `value` contains all the passed `keys`. Either as keys in a dictionary or elements in an array. If `value` is neither of those types, `false` is returned.
- `#test.is-type( t, value )`: Tests if `value` is of type `t`.
- `#test.is-elem( func, value )`: Tests if `value` is a content element with `value.func() == func`. If `func` is a string, `value` will be compared to `repr(value.func())` instead.Both of these effectively do the same:
```typst
#test.is-elem(raw, some_content)
#test.is-elem("raw", some_content)
```
- `#test.any-type( ..types, value )`: Tests if `value` has any of the passed-in types.
- `#test.same-type( ..values )`: Tests if all passed-in values have the same type.
- `#test.all-of-type( t, ..values )`: Tests if all of the passed-in values have the type `t`.
- `#test.none-of-type( t, ..values )`: Tests if none of the passed-in values has the type `t`.
- `#test.one-not-none( ..values )`: Checks, if at least one value in `values` is not equal to `none`. Useful for checking multiple optional arguments for a valid value: `#if is.one-not-none(..args.pos()) [ #args.pos().find(is.not-none) ]`- `#test.is-sequence( value )`: Tests if `value` is a sequence of content.
- `#test.is-raw( value )`: Tests if `value` is a raw element.
- `#test.is-table( value )`: Tests if `value` is a table element.
- `#test.is-list( value )`: Tests if `value` is a list element.
- `#test.is-enum( value )`: Tests if `value` is an enum element.
- `#test.is-terms( value )`: Tests if `value` is a terms element.
- `#test.is-cols( value )`: Tests if `value` is a columns element.
- `#test.is-grid( value )`: Tests if `value` is a grid element.
- `#test.is-stack( value )`: Tests if `value` is a stack element.
- `#test.is-label( value )`: Tests if `value` is of type `label`.### Default values
```typst
#import "@preview/t4t:0.4.2": def
```These functions perform a test to decide if a given `value` is _invalid_. If the test _passes_, the default `def` is returned, `value` otherwise.
Almost all functions support an optional `do` argument to be set to a function of one argument that will be applied to the value if the test fails. For example:
```typst
// Sets date to a datetime from an optional
// string argument in the format "YYYY-MM-DD"
#let date = def.if-none(
passed_date, // passed-in argument
def: datetime.today(), // default
do: (d) >= { // post-processor
d = d.split("-")
datetime(year=d[0], month=d[1], day=d[2])
}
)
```Note that previous versions of these functions got the default passed in as the first positional argument. Since Version 0.4.0 the default is now a named argument in favor of more readable code. To restore the old behaviour, you can import the `def.compat` module as `def`:
```typst
#import "@preview/t4t:0.4.2": def
#import def.compat as def
```- `#def.if-true( value, test, def:none, do:none )`: Returns `def` if `test` is `true`, `value` otherwise.
- `#def.if-false( value, test, def:none, do:none )`: Returns `def` if `test` is `false`, `value` otherwise.
- `#def.if-none( value, def:none, do:none )`: Returns `def` if `value` is `none`, `value` otherwise.
- `#def.if-auto( value, def:none, do:none )`: Returns `def` if `value` is `auto`, `value` otherwise.
- `#def.if-any( value, ..compare, def:none, do:none )`: Returns `def` if `value` is equal to any of the passed-in values, `value` otherwise. (`#def.if-any(none, auto, 1pt, width)`)
- `#def.if-not-any( value, ..compare, def:none, do:none )`: Returns `def` if `value` is not equal to any of the passed-in values, `value` otherwise. (`#def.if-not-any(left, right, top, bottom, position)`)
- `#def.if-empty( def:none, do:none, value )`: Returns `def` if `value` is _empty_, `value` otherwise.
- `#def.as-arr( ..values )`: Always returns an array containing all `values`. Any arrays in `values` will be flattened into the result. This is useful for arguments, that can have one element or an array of elements: `#def.as-arr(author).join(", ")`.### Assertions
```typst
#import "@preview/t4t:0.4.2": assert
```This submodule overloads the default `assert` function and provides more asserts to quickly check if given values are valid. All functions use `assert` in the background.
Since a module in Typst is not callable, the `assert` function is now available as `assert.that()`. `assert.eq` and `assert.ne` work as expected.
All assert functions take an optional argument `message` to set the error message shown if the assert fails.
- `#assert.that( test )`: Asserts that the passed `test` is `true`.
- `#assert.that-not( test )`: Asserts that the passed `test` is `false`.
- `#assert.eq( a, b )`: Asserts that `a` is equal to `b`.
- `#assert.ne( a, b )`: Asserts that `a` is not equal to `b`.
- `#assert.neq( a, b )`: Alias for `assert.ne`.
- `#assert.not-none( value )`: Asserts that `value` is not equal to `none`.
- `#assert.any( ..values, value )`: Asserts that `value` is one of the passed `values`.
- `#assert.not-any( ..values, value )`: Asserts that `value` is not one of the passed `values`.
- `#assert.any-type( ..types, value )`: Asserts that the type of `value` is one of the passed `types`.
- `#assert.not-any-type( ..types, value )`: Asserts that the type of `value` is not one of the passed `types`.
- `#assert.all-of-type( t, ..values )`: Asserts that the type of all passed `values` is equal to `t`.
- `#assert.none-of-type( t, ..values )`: Asserts that the type of all passed `values` is not equal to `t`.
- `#assert.not-empty( value )`: Asserts that `value` is not _empty_.
- `#assert.new( test )`: Creates a new assert function that uses the passed `test`. `test` is a function with signature `(any) => boolean`. This is a quick way to create an assertion from any of the `is` functions:```typst
#let assert-foo = assert.new(is.eq.with("foo"))#let assert-length = assert.new(is.length)
```## Element helpers
```typst
#import "@preview/t4t:0.4.2": get
```This submodule is a collection of functions, that mostly deal with content elements and _get_ some information from them. Though some handle other types like dictionaries.
- `#get.dict( ..values )`: Create a new dictionary from the passed `values`. All named arguments are stored in the new dictionary as is. All positional arguments are grouped in key-value pairs and inserted into the dictionary:
```typst
#get.dict("a", 1, "b", 2, "c", d:4, e:5)// (a:1, b:2, c:none, d:4, e:5)
```
- `#get.dict-merge( ..dicts )`: Recursively merges the passed-in dictionaries:```typst
#get.dict-merge(
(a: 1),
(a: (one: 1, two:2)),
(a: (two: 4, three:3))
)// (a:(one:1, two:4, three:3))
```
- `#get.args( args, prefix: "" )`: Creates a function to extract values from an argument sink `args`.The resulting function takes any number of positional and named arguments and creates a dictionary with values from `args.named()`. Positional arguments are present in the result if they are present in `args.named()`. Named arguments are always present, either with their value from `args.named()` or with the provided value.
A `prefix` can be specified, to extract only specific arguments. The resulting dictionary will have all keys with the prefix removed, though.
```typst
#let my-func( ..options, title ) = block(
..get.args(options)(
"spacing", "above", "below",
width:100%
)
)[
#text(..get.args(options, prefix:"text-")(
fill:black, size:0.8em
), title)
]#my-func(
width: 50%,
text-fill: red, text-size: 1.2em
)[#lorem(5)]
```
- `#get.text( element, sep: "" )`: Recursively extracts the text content of a content element.
If present, all child elements are converted to text and joined with `sep`.
- `#get.stroke-paint( stroke, default: black )`: Returns the color of `stroke`. If no color information is available, `def` is used. (Deprecated, use `stroke.paint` instead.)
- `#get.stroke-thickness( stroke, default: 1pt )`: Returns the thickness of `stroke`. If no thickness information is available, `def` is used. (Deprecated, use `stroke.thickness` instead.)
- `#get.stroke-dict( stroke, ..overrides )`: Creates a dictionary with the keys necessary for a stroke. The returned dictionary is guaranteed to have the keys `paint`, `thickness`, `dash`, `cap` and `join`.If `stroke` is a dictionary itself, all key-value pairs are copied to the resulting stroke. Any named arguments in `overrides` will override the previous value.
- `#get.inset-at( direction, inset, default: 0pt )`: Returns the inset (or outset) in a given `direction`, ascertained from `inset`.
- `#get.inset-dict( inset, ..overrides )`: Creates a dictionary usable as an inset (or outset) argument.The resulting dictionary is guaranteed to have the keys `top`, `left`, `bottom` and `right`.
If `inset` is a dictionary itself, all key-value pairs are copied to the resulting stroke. Any named arguments in `overrides` will override the previous value.
- `#get.x-align( align, default:left )`: Returns the alignment along the x-axis from the passed-in `align` value. If none is present, `def` is returned. (Deprecated, use `align.x` instead.)```typst
#get.x-align(top + center) // center
```
- `#get.y-align( align, default:top )`: Returns the alignment along the y-axis from the passed-in `align` value. If none is present, `def` is returned. (Deprecated, use `align.y` instead.)## Math functions
```typst
#import "@preview/t4t:0.4.2": math
```Some functions to complement the native `calc` module.
- `#math.minmax( a, b )`: Returns an array with the minimum of `a` and `b` as the first element and the maximum as the second:
```typst
#let (min, max) = math.minmax(a, b)
```
- `#math.clamp( min, max, value )`: Clamps a value between `min` and `max`. In contrast to `calc.clamp()` this function works for other values than numbers, as long as they are comparable.```typst
text-size = math.clamp(0.8em, 1.2em, text-size)
```
- `#lerp( min, max, t )`: Calculates the linear interpolation of `t` between `min` and `max`.```typst
#let width = math.lerp(0%, 100%, x)
````t` should be a value between 0 and 1, but the interpolation works with other values, too. To constrain the result into the given interval, use `math.clamp`:
```typst
#let width = math.lerp(0%, 100%, math.clamp(0, 1, x))
```
- `#map( min, max, range-min, range-max, value )`: Maps a `value` from the interval `[min, max]` into the interval `[range-min, range-max]`:```typst
#let text-weight = int(math.map(8pt, 16pt, 400, 800, text-size))
```