Did someone had a look at Typst plugin system?

Hello.

The way I labeled the subject, it may appear quite far from OCaml :wink:.

Typst is an interesting markup-based typesetting system. It’s fast. The language has a lot of functional traits.

Typst plugins are based on Webassembly modules. I think that OCaml can now target Wasm.

But both Typst and OCaml have some constraint regarding Wasm: I wonder whether both worlds meet somewhere, allowing us to write Typst plugins in OCaml?

Bye

It seems possible in principle… provided that Typst’s Wasm engine supports the Wasm GC extension, which I’m not certain about. In my understanding however, that extension should make its way into the standard soon.

It also requires to compile OCaml to Wasm modules that don’t depend on a Javascript environment, which is not the case of the files produced by the current wasm_of_ocaml, but is a work in progress. I don’t know about Wasocaml, maybe it would allow it more easily.

It would also likely require some code generation to make the glue between the very low-level interface required by Typst (some integers and a buffer) and OCaml parameters and return value.

Thank you for your answer. I did not express it directly, but yes, my fearing was about the GC extension.
Will ask Typst people.

Nice calendar coincidence that a new version of both pieces of code had a new release a couple of days ago. :wink:

Best regards

If you do get anywhere, keep me updated too!

Wasmi currently doesn’t support GC, but Wasmtime does, and has a very similar interface to Wasmi, so the conversion isn’t too difficult (side-note, I’m neither a typst, wasmi or wasmtime developer, nor do I use Rust regularly, so there might be some issues in that conversion – any are my fault and any that didn’t make it there are due to Rust’s type system).

But I haven’t got any further with it than this.

An alternative could be to use typst query, e.g.

Here is some OCaml code
```ocaml
let x = 1 + 2;;
``` <ocaml>
And here is some more
```ocaml
print_endline "Hello, world!";;
``` <ocaml>

Then if you do typst query test.typ '<ocaml>' it gives you a JSON list of dicts containing text e.g.

❯ typst query test.typ '<ocaml>' | jq '.[].text'
"let x = 1 + 2;;"
"print_endline \"Hello, world!\";;"

And it could be possible to write a program to pipe these into OCaml, and pipe the output back. Here is a (slow) shell script to do that

#!/usr/bin/env bash

set -euo pipefail

socat exec:"utop -emacs" unix-listen:./utop.socket,fork,unlink-early &

eval "inputs=($(typst query "$1" "<ocaml>" | jq -r '.[].text | @sh'))"

echo '#let results = (' >output.typ
for input in "${inputs[@]}"; do
  echo 'input:' | socat unix:./utop.socket -
  echo "${input}" | sed -n 's/^/data:/p' | socat unix:./utop.socket -
  echo "data:;;" | socat unix:./utop.socket -
  {
    echo '[```ocaml'
    echo 'end:' | socat unix:./utop.socket - | sed -n 's/^stdout://p'
    echo '```],'
  } >>output.typ
done

echo ')' >>output.typ
echo $'input:\ndata:#quit;;\nend:' | socat unix./utop.socket -

Looking at typst/Cargo.toml at main · typst/typst · GitHub, it seems that Typst is using wasmi as a WebAssembly interpreter.

wasmi web page lists how Webassembly feature extensions are supported.

  • I don’t know if “Unlikely to be supported” for simd and relaxed-simd is an issue?
  • and gc, threads, exception-handling, function-references , … are “Not yet implemented.”
    So… I think that we’ll have to wait.

Best regards

Yes sorry I burried the lead and wasn’t clear. Typst is using wasmi but converting from wasmi to wasmtime is reasonably straight forward, see

Which takes me from

❯ typst compile test.typ
error: failed to load WebAssembly module (invalid leading byte (0x50) for type (at offset 0xc))
  ┌─ test.typ:1:16
  │
1 │ #let p = plugin("a.out.wasm")
  │                 ^^^^^^^^^^^^

to

❯ ~/programming/rust/typst/target/debug/typst compile test.typ
error: plugin does not export its memory
  ┌─ test.typ:1:16
  │
1 │ #let p = plugin("a.out.wasm")
  │                 ^^^^^^^^^^^^

which is progress! (There were earlier errors about not loading in wasmtime too, because I hadn’t enabled the GC extension, see the last commit.)