To-Stuff is a small package of Typst functions for converting string values to native types. This is most useful when loading layout data from an external configuration source, such as a YAML file.
How To Use
Import the module into the current scope, optionally renamed using the as
keyword:
#import "@preview/to-stuff:0.2.0"
// Bindings available as to-stuff.alignment(), to-stuff.angle(), etc.
// …or…
#import "@preview/to-stuff:0.2.0" as to
// Bindings available as to.alignment(), to.angle(), etc.
The module’s let
bindings have the same names as their return types, and rely on Typst’s import
syntax to scope safely. It is not recommended to load the individual bindings into the current scope, as that may cause collisions with the types themselves.
#import "@preview/to-stuff:0.2.0": *
// NOT RECOMMENDED
// Bindings will collide with built-in types: alignment, angle, etc.
Localisation
All conversions involving numeric values assume the number strings to be in a format understood by Typst code; specifically:
- All numeric digits must be ASCII characters 0-9.
- Decimals are indicated by a period; commas and other international decimal signs are not supported.
- Thousands separators are not supported.
Functions
alignment()
Attempts to convert a value to an alignment
.
#alignment(
str|alignment|dictionary,
quiet: bool,
) -> none|alignment
View arguments
value
str
or alignment
or dictionary
(positional, required)
The value that should be converted to an alignment
.
- An
alignment
is returned unchanged. - A string representation of any of the eight
alignment
values is converted to that value.- If the string includes the
alignment.…
scoping prefix, the conversion fails.
- If the string includes the
- A string consisting of two
alignment
representations joined by a plus sign is converted to the corresponding 2D alignment, provided the two strings do not correspond to alignments on the same axis. - A
dictionary
containing one or more of the keysx
andy
, and no other keys, is converted.- The value of
x
, if present, must be either a horizontalalignment
or a value that would convert to one. - The value of
y
, if present, must be either a verticalalignment
or a value that would convert to one.
- The value of
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.alignment("top + right")
// -> right + top
#let b = to.alignment(top + right)
// -> right + top
#let c = to.alignment((x: "right", y: "top"))
// -> right + top
#let d = to.alignment("turnwise")
// panics with: "could not convert to alignment: \"turnwise\""
#let e = to.alignment("top + bottom")
// panics with: "cannot add two vertical alignments: \"top + bottom\""
#let f = to.alignment(quiet: true, "top + bottom")
// -> none
angle()
Attempts to convert a value to an angle
.
#angle(
str|angle,
quiet: bool,
) -> none|angle
View arguments
value
str
or angle
(positional, required)
The value that should be converted to an angle
.
- An
angle
is returned unchanged. - A string representation of a number followed by the letters
deg
orrad
is converted.- The number may be positive or negative, and may contain decimal places.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.angle("45deg")
// -> 45deg
#let b = to.angle(45deg)
// -> 45deg
#let c = to.angle("42")
// panics with: "could not convert to angle: \"42\""
#let d = to.angle(quiet: true, "42")
// -> none
color()
Attempts to convert a value to a color
.
#angle(
str|color,
quiet: bool,
) -> none|color
View arguments
value
str
or color
(positional, required)
The value that should be converted to a color
.
- A
color
is returned unchanged. - A string representation of a predefined color value is converted to that built-in color.
- A string representation of a hash symbol followed by a 6- or 8-digit hexadecimal code is converted to the corresponding RGB or RGBA value.
- A string representation of a color space function followed by parentheses and arguments is converted.
- If the string includes the
color.…
scoping prefix, the conversion fails. This includes thehsl
,hsv
, andlinear-rgb
functions.
- If the string includes the
Note: Color space function arguments are not currently checked for validity before the string is passed to eval()
. Invalid function arguments causes a native Typst syntax error rather than a panic; this error cannot be suppressed by setting quiet
to true
(see below). This may change in a future version.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.color("red")
// -> rgb("#ff4136")
#let b = to.color(red)
// -> rgb("#ff4136")
#let c = to.color("#FF4136FF")
// -> rgb("#ff4136")
#let d = to.color("rgb(255, 65, 54)")
// -> rgb("#ff4136")
#let e = to.color("hsv(135deg,75%,127,100)")
// -> color.hsv(135deg, 75%, 49.8%, 39.22%)
#let f = to.color("indigo")
// panics with: "could not convert to color: \"indigo\""
#let g = to.color(quiet: true, "indigo")
// -> none
direction()
Attempts to convert a value to a direction
.
#direction(
str|direction,
quiet: bool,
) -> none|direction
View arguments
value
str
or direction
(positional, required)
The value that should be converted to a direction
.
- A
direction
is returned unchanged. - A string representation of any of the four
direction
values is converted to that value.- If the string includes the
direction.…
scoping prefix, the conversion fails.
- If the string includes the
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.direction("rtl")
// -> rtl
#let b = to.direction(rtl)
// -> rtl
#let c = to.direction("btf")
// panics with: "could not convert to direction: \"btf\""
#let d = to.direction(quiet: true, "btf")
// -> none
fraction()
Attempts to convert a value to a fraction
.
#fraction(
str|fraction,
quiet: bool,
) -> none|fraction
View arguments
value
str
or fraction
(positional, required)
The value that should be converted to a fraction
.
- A
fraction
is returned unchanged. - A string representation of a number followed by the letters
fr
is converted.- The number may be positive or negative, and may contain decimal places.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.fraction("2.5fr")
// -> 2.5fr
#let b = to.fraction(2.5fr)
// -> 2.5fr
#let c = to.fraction("42")
// panics with: "could not convert to fraction: \"42\""
#let d = to.fraction(quiet: true, "42")
// -> none
length()
Attempts to convert a value to a length
.
#length(
str|length,
quiet: bool,
) -> none|length
View arguments
value
str
or length
(positional, required)
The value that should be converted to a length
.
- A
length
is returned unchanged. - A string representation of a number followed by the letters
pt
,mm
,cm
,in
, orem
, is converted.- The number may be positive or negative, and may contain decimal places.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.length("45pt")
// -> 45pt
#let b = to.length(45pt)
// -> 45pt
#let c = to.length("42")
// panics with: "could not convert to length: \"42\""
#let d = to.length(quiet: true, "42")
// -> none
ratio()
Attempts to convert a value to a ratio
.
#ratio(
str|ratio,
quiet: bool,
) -> none|ratio
View arguments
value
str
or ratio
(positional, required)
The value that should be converted to a ratio
.
- A
ratio
is returned unchanged. - A string representation of a number followed by a percent sign is converted.
- The number may be positive or negative, and may contain decimal places.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.ratio("45%")
// -> 45%
#let b = to.ratio(45%)
// -> 45%
#let c = to.ratio("42")
// panics with: "could not convert to ratio: \"42\""
#let d = to.ratio(quiet: true, "42")
// -> none
relative()
Attempts to convert a value to a relative
.
#relative(
str|relative|ratio|length|dictionary,
quiet: bool,
) -> none|relative
View arguments
value
str
or relative
or ratio
or length
or dictionary
(positional, required)
The value that should be converted to a relative
.
- A
relative
is returned unchanged. - A
ratio
is returned as arelative
with alength
of0pt
. - A
length
is returned as arelative
with aratio
of0%
. - A string representation of a
ratio
(see above) is converted. - A string representation of a
length
(see above) is converted. - A string consisting of multiple
ratio
s andlengths
joined by plus signs or minus signs is converted to a singlerelative
length.- All
length
-like substrings are added. - All
ratio
-like substrings are added.
- All
- A
dictionary
containing one or more of the keysratio
andlength
, and no other keys, is converted.- The value of
ratio
, if present, must be either aratio
or a value that would convert to one. - The value of
length
, if present, must be either alength
or a value that would convert to one.
- The value of
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.relative("45pt + 3%")
// -> 3% + 45pt
#let b = to.relative(45pt + 3%)
// -> 3% + 45pt
#let c = to.relative((ratio: "3%", length: "45pt"))
// -> 3% + 45pt
#let d = to.relative("42")
// panics with: "could not convert to relative: \"42\""
#let e = to.relative(quiet: true, "42")
// -> none
stroke()
Attempts to convert a value to a stroke
.
#stroke(
str|stroke|color|length|array|dictionary,
quiet: bool,
) -> none|stroke
View arguments
value
str
or stroke
or color
or length
or array
or dictionary
(positional, required)
The value that should be converted to a stroke
.
- A
stroke
,color
orlength
is returned unchanged. - A string representation of a
color
(see above) is converted. - A string representation of a
length
(see above) is converted. - A valid dash pattern is converted.
- A string representation of one or more valid
color
s,length
s and/or predefined dash patterns joined by plus signs is converted.- All
color
-like substrings are combined viacolor.mix()
. - All
length
-like substrings added.
- All
- A
dictionary
that would otherwise be accepted as a validstroke
is converted.
quiet
bool
Whether to return none
if the value could not be converted. If false
, invalid values cause a panic.
Default: false
View examples
#import "@preview/to-stuff:0.2.0" as to
#let a = to.stroke("red")
// -> rgb("#ff4136")
#let b = to.stroke(45pt)
// -> 45pt
#let c = to.stroke("densely-dashed")
// -> (dash: array(3pt, 2pt), phase: 0pt)
#let d = to.stroke((3pt, 2pt))
// -> (dash: array(3pt, 2pt), phase: 0pt)
#let e = to.stroke((paint: red, thickness: 2pt, dash: "densely-dashed"))
// -> (paint: rgb("#ff4136"), thickness: 2pt, dash: (array: (3pt, 2pt), phase: 0pt))
#let f = to.stroke("2pt + red + densely-dashed + silver + 5pt")
// -> (paint: oklab(77.85%, 0.1, 0.054), thickness: 7pt, dash: (array: (3pt, 2pt), phase: 0pt))
#let g = to.stroke("deep-dish")
// panics with: "could not convert to stroke: \"deep-dish\""
#let h = to.stroke(quiet: true, "deep-dish")
// -> none
Development
Requirements
Local development of To-Stuff relies on the following software:
Setup
-
Fork the Typst Packages repository and clone it locally. A sparse checkout is recommended.
For demonstration purposes, we assume your local clone of your Typst Packages fork is at
~/my-typst-dev/universe
. -
Clone this repository.
cd ~/my-typst-dev git clone https://codeberg.org/boondoc/typst-to-stuff
-
Create and activate an environment file to link To-Stuff’s
taskfile
to your local copy of Typst Packages. You may need to edit yourdirenv
settings to recognise.env
files.cd ~/my-typst-dev/typst-to-stuff echo "LOCAL_UNIVERSE=${HOME}/my-typst-dev/universe/packages/preview" > .env direnv allow
Note that the above command should write an absolute path to
.env
;task
seems not to parse shell variables inside.env
files, even whendirenv
itself expands them correctly. -
Initialise tests.
cd ~/my-typst-dev/typst-to-stuff task
The default
task
operation runs all unit tests once. -
Begin monitoring the repository for file edits.
cd ~/my-typst-dev/typst-to-stuff task watch
Running the
watch
task in a clean repository can incorrectly skip several tests, taking multiple refreshes to successfully compile the entire suite; running a single pass first (see step 4) seems to solve the problem.
Updating the project version
To set a new project version:
- Edit the
package.version
setting intypst.toml
- Run
task docs
to automatically update theREADME.md
file to reflect the correct version number.
Packaging for Universe
Running task package
will copy selected files to the the path specified in $LOCAL_UNIVERSE
(set in .env
), under a subdirectory structure according to the project name and version specified in typst.toml
. The list of files copied is defined in taskfile.yml
under vars.MODULE
and vars.IGNORE
.
Only files relevant to Typst Universe itself should be packaged in this way; for instance, Universe has no use for the tests
subdirectory.