sir-lancebot icon indicating copy to clipboard operation
sir-lancebot copied to clipboard

Add Typst support

Open RundownRhino opened this issue 1 year ago • 3 comments

Description

Add a .typst command, working similarly to .latex but for rendering Typst.

Reasoning

The bot's .latex command has been notoriously unstable in the past, but nowadays is mostly working. However, it's pretty hard to consistently write correct LaTeX snippets on the first try, and the error logs are not especially helpful because LaTeX logs rarely are. It would be nice to have a simpler alternative for quickly writing some simple math, and Typst would fill that niche - Typst source code is much more readable and doesn't require an explicit preamble. The following is an (entire!) typst document:

$lim_(h -> 0) (f(x + h) - f(x))/h$

which renders to: Image

Proposed Implementation

Typst has a Python library, so the implementation should be straightforward. Here's a proof of concept:

import typst
from tempfile import NamedTemporaryFile
from PIL import Image

s = """$lim_(h -> 0) (f(x + h) - f(x))/h$"""
with NamedTemporaryFile("w", encoding="utf-8") as inp, NamedTemporaryFile("rb", suffix=".png") as out:
    inp.write(s)
    inp.flush()
    typst.compile(inp.name, out.name)
    img = Image.open(out)
    img.load()
img.show()

An interesting detail is the handling of third-party packages. The Latex cog is currently implemented as having a specific set of whitelisted packages available. Typst, meanwhile, by default supports importing arbitrary packages at runtime to be downloaded during the compilation process - which in theory is safe because typst plugins are required to be pure functions that get compiled to WASM. Nevertheless, probably at first it'd be best to only allow a shortlist of popular packages, but in the future we could consider removing that limit.

Would you like to implement this yourself?

  • [X] I'd like to implement this feature myself
  • [X] Anyone can implement this feature

RundownRhino avatar Nov 02 '24 22:11 RundownRhino

Have you considered using io.BytesIO? Or does the library not support it?

mbaruh avatar Nov 08 '24 15:11 mbaruh

It looks like it does support not writing an output file (just need to not pass output). I'll change the implementation to use that. It will come with the problem that a maliciously constructed input can return an arbitrarily big bytes object, but I can probably fix this by setting a an rlimit on memory usage for the worker process.

RundownRhino avatar Nov 08 '24 15:11 RundownRhino

If you're worried about a maliciously large output, that's probably a good idea regardless of the method

mbaruh avatar Nov 08 '24 15:11 mbaruh