Skip to content

math_spec.typeset.typst

Typst. The format that compiles without a toolchain.

Here to keep :mod:math_spec.typeset.format honest: a seam with one implementation behind it is a shape, not an abstraction. Typst's syntax differs from LaTeX's in every respect that matters — sum_(…), cal(T), function-call grouping instead of brace groups, a term list instead of a description environment — so if the walk needed changing to accommodate it, the split was in the wrong place.

Practically: the compiler is one self-contained binary (a pip wheel, so the suite compiles every example without apt), and multi-letter identifiers in math are upright by default, which is why names go through italic("…").

TypstFormat #

See :class:math_spec.typeset.format.Format.

The cyclic operators spell with .o, Typst's circled modifier; minus.circle does not compile.

dash = '---' class-attribute #

notation = 'typst' class-attribute #

operators = {'cdot': 'dot', 'plus': '+', 'minus': '-', 'equal': '=', 'le': '<=', 'ge': '>=', 'lt': '<', 'gt': '>', 'ne': '!=', 'in': 'in', 'and': 'and', 'or': 'or', 'not': 'not', 'true': 'top', 'false': 'bot', 'forall': 'forall', 'such_that': 'colon', 'infinity': 'infinity', 'minus_infinity': '-infinity', 'cyclic_minus': 'minus.o', 'cyclic_plus': 'plus.o', 'edge_minus': 'minus.square', 'edge_plus': 'plus.square', 'times': 'times', 'maps_to': 'arrow.r', 'reals': 'RR', 'integers': 'ZZ', 'binary_set': '{0, 1}', 'sos_set': 'upright("SOS")', 'position': 'upright("pos")', 'minimize': 'min', 'maximize': 'max'} class-attribute #

suffix = '.typ' class-attribute #

apply(function, argument) #

f(x) in Typst math is a call on f.

With an upright("bus") head that is exactly the notation wanted, and it needs no thin space.

Source code in src/math_spec/typeset/typst.py
def apply(self, function: str, argument: str) -> str:
    """``f(x)`` in Typst math is a call on ``f``.

    With an ``upright("bus")`` head that is exactly the notation wanted,
    and it needs no thin space.
    """
    return f'{function}({argument})'

cardinality(inner) #

Source code in src/math_spec/typeset/typst.py
def cardinality(self, inner: str) -> str:
    return f'abs({inner})'

cases(arms) #

Source code in src/math_spec/typeset/typst.py
def cases(self, arms: list[tuple[str, str]]) -> str:
    rows = ', '.join(f'{value} & upright("if ") {condition}' for value, condition in arms)
    return f'cases({rows})'

document(blocks, *, standalone) #

Join the blocks; standalone only decides whether page setup is emitted.

Typst has no preamble/body split — a bare fragment is already a document.

Source code in src/math_spec/typeset/typst.py
def document(self, blocks: list[str], *, standalone: bool) -> str:
    """Join the blocks; ``standalone`` only decides whether page setup is emitted.

    Typst has no preamble/body split — a bare fragment is already a document.
    """
    body = '\n\n'.join(blocks) + '\n'
    return f'{_PREAMBLE}\n{body}' if standalone else body

equations(lines, *, numbered) #

A block equation, aligned on &.

Typst aligns on & inside a block equation exactly as amsmath does, so the :class:Line split carries over unchanged — which is the point.

Source code in src/math_spec/typeset/typst.py
def equations(self, lines: list[Line], *, numbered: bool) -> str:
    """A block equation, aligned on ``&``.

    Typst aligns on ``&`` inside a block equation exactly as amsmath
    does, so the :class:`Line` split carries over unchanged — which is
    the point.
    """
    rows = [
        f'{self.prose(line.label) if line.label else ""} & {line.left} & {line.right} & {line.condition}'.rstrip(
            ' &'
        )
        for line in lines
    ]
    body = ' \\\n  '.join(rows)
    numbering = '#set math.equation(numbering: "(1)")\n' if numbered else ''
    return f'{numbering}$ {body} $'

escape(prose) #

Source code in src/math_spec/typeset/typst.py
def escape(self, prose: str) -> str:
    return _escape(prose)

fraction(numerator, denominator) #

Source code in src/math_spec/typeset/typst.py
def fraction(self, numerator: str, denominator: str) -> str:
    return f'frac({numerator}, {denominator})'

glossary(title, entries) #

Source code in src/math_spec/typeset/typst.py
def glossary(self, title: str, entries: list[Entry]) -> str:
    rows = '\n'.join(f'/ {self.math(e.symbol)}: {e.meaning(self.dash)}' for e in entries)
    return f'== {title}\n{rows}'

greek(name) #

Source code in src/math_spec/typeset/typst.py
def greek(self, name: str) -> str:
    return name

italic(name) #

Source code in src/math_spec/typeset/typst.py
def italic(self, name: str) -> str:
    return f'italic({_quote(name)})'

joined(parts, operator) #

Source code in src/math_spec/typeset/typst.py
def joined(self, parts: list[str], operator: str) -> str:
    return f' {operator} '.join(parts) if operator else ', '.join(parts)

math(expression) #

Source code in src/math_spec/typeset/typst.py
def math(self, expression: str) -> str:
    return f'${expression}$'

mono(text) #

Source code in src/math_spec/typeset/typst.py
def mono(self, text: str) -> str:
    return _raw(text)

note(text) #

Source code in src/math_spec/typeset/typst.py
def note(self, text: str) -> str:
    return text

parenthesise(inner) #

Source code in src/math_spec/typeset/typst.py
def parenthesise(self, inner: str) -> str:
    return f'({inner})'

prose(text) #

Source code in src/math_spec/typeset/typst.py
def prose(self, text: str) -> str:
    return f'upright({_quote(text)})'

script(letter) #

Source code in src/math_spec/typeset/typst.py
def script(self, letter: str) -> str:
    return f'cal({letter})'

section(title, body) #

Source code in src/math_spec/typeset/typst.py
def section(self, title: str, body: str) -> str:
    return f'== {title}\n{body}'

subscript(base, indices) #

Source code in src/math_spec/typeset/typst.py
def subscript(self, base: str, indices: list[str]) -> str:
    return f'{base}_({",".join(indices)})' if indices else base

summation(domain, body) #

Source code in src/math_spec/typeset/typst.py
def summation(self, domain: str, body: str) -> str:
    return f'sum_({domain}) {body}'

superscript(base, tail) #

Source code in src/math_spec/typeset/typst.py
def superscript(self, base: str, tail: str) -> str:
    return f'{base}^({tail})'

upright(name) #

Source code in src/math_spec/typeset/typst.py
def upright(self, name: str) -> str:
    return f'upright({_quote(name)})'