TYPST: A new markup + page layout engine to take on LaTeX

Eh, I don’t feel I should install Homebrew in my work system. I’ll have to wait for a standard installer, or for Quarto to improve compatibility.

But isn’t Quarto just using the original Typst CLI?

Paolo

I discovered the first of my mistakes: I was invoking directly typst, when using the quarto typst compile command. I should have used the quarto render command, instead. The typst conversion happens internally to Quarto, with no need to invoke it.

I could make my first simple PDF file with Typst. However, I could also find some bugs to be reported with more complex files. Maybe it is a bit too early to use this route. But I feel this is the right one.

Paolo

Quarto is really Pandoc + a whole bunch of additional Lua filters and templates all wrapped in a single app. Quarto itself cannot replace Pandoc as Quarto is “opinionated”, it forces its idea of which filters and template you should use. You can work around this using extensions and publishing templates but just be aware this is extra complexity…

You don’t need homebrew to install anything. Pandoc has an installer, as does Quarto, as does Typst, so I don’t quite understand your problem? Homebrew just makes everything much much easier, your choice…

Quarto is an opinionated Pandoc so it doesn’t use Typst at all, but provides a wrapper around Pandoc’s commands. Pandoc uses the already installed Typst CLI, so it provides the same features as whatever version you installed. BUT Pandoc does convert markdown to Typst markup, and that means if you want **strong** to become *strong* then it is Pandoc doing that. So Typst does the job of typst⇨PDF, Pandoc does the job of markdown⇨typst and Scrivener does the job of RTF+Binder⇨markdown.

Just to reiterate – the most direct workflow is a markdown based Scrivener > Pandoc > Typst. This gives you maximal flexibility to define the layout etc. You can replace Pandoc with Quarto if you know how to debug that extra layer of complexity, or not get confused by this extra layer between pandoc and typst…

It seems with the current prerelease (V1.4), my assertion is no longer the case.

So they are going to bundle the full typst-cli (currently bundling V0.8) into Quarto. It seems they are also modifying the Pandoc templates: GitHub - jgm/pandoc-templates: Templates for pandoc, tagged to release – with their own tweaks as well as bundling some modified templates from the Typst team. Typst support is still missing quite a few Quarto features, but I suspect they aim to make this an alternative to LaTeX for PDF generation in the longer term?

For straight Pandoc users, the pagebreak filter has a pull to support typst output now: pagebreak: add support for Typst by s22h · Pull Request #2 · pandoc-ext/pagebreak · GitHub – in the meantime my version of this filter already includes these changes: dotpandoc/filters/pagebreak.lua at master · iandol/dotpandoc · GitHub

I attach an updated Typst sample project:

Typst.scriv.zip (369.7 KB)

This is built to compile and produce a Typst PDF and demonstrates the Scrivener workflow: custom styles and section types to build markup. It is mostly built around Pandoc Markdown, so we can benefit from all the existing Scrivener tools for markdown output (heading levels, conversion of RTF lists and tables, figures with captions, footnotes etc.) and use the many features that Pandoc offers.


But I also made a really quick-n-dirty direct-to-Typst compile format, Select Compile to Plain Text and choose “Pure Typst” and you get Typst output and the post processor runs Typst directly:

Currently some of the markdown sections of the content (like maths) are just turned to code to get it to compile. Scrivener’s lists don’t work, the title page is missing, and some styles are not set up, but at least captioned figures and footnotes are working. There is more work that needs to be done but Scrivener is able to build complex Typst document directly, given the caveats I mention above…

Also, Typst has a package system that is growing so quickly, lots of very useful packages are already available:

You can import packages in your document by placing import lines in your metadata template header. So for example in your header add this (I needed to specify the functions like info, error etc to import explicitly):

// Import some packages
#import "@preview/gentle-clues:0.3.0": info, success, warning, error

Then in the Scrivener document use a Raw Typst style and enter e.g.:

#info[This info box comes from the gentle-clues package that is imported by the headers above. #lorem(50)]

To get an info box:

Screenshot 2023-10-24 at 15.10.12

This is demonstrated in the Typst Project linked above…

V0.9 has just been released:

Highlights are CSL support for bibliographies, blockquote support and a bunch of other stuff.

Also I never checked but the installer is only 9.7MB (~28MB unpacked) which is pretty amazing for a full PDF layout engine!!!

Update to my Scrivener template:

Typst.scriv.zip (337.8 KB)

Figures with captions and citations are working (pure typst uses .bib and pandoc uses .json, both included, but there are some formatting differences in how to insert citations), two heading levels for pure and a few other bits.

2 Likes

@AmberV — in §21.5.1 Compile Folder you cover the way to not make a folder on compilation for MMD (append -mmd for example) etc. — how can I get this to work for Plain Text outputs that also generate multiple files? I tried folder-mmd, folder-txt, folder-typ, folder.typ etc. but it still generates a name.typ subfolder. I need to put the BIBTEX file there and my workaround is to use Finder to “lock” the file.bib file so Scrivener cannot delete it but there must be a better way? If I don’t lock file.bib it gets deleted each compile which was not what I expected and never happens for MMD output…

1 Like

I’ve got the previous version of your template working well with the Raw Typst style, but I need more experimenting with the Raw Typst section type with my own tables. But I’ll crack what I’m doing wrong.

However, my next post was going to be about bibliography, and this seems opportune. The command line you use uses citeproc with the bibliography in “core”. I use Bookends and have created a .bib from it. What do I change the command to… cite, citep …? I have no experience of this having always used Bookends scan in NWP.

Mark

PS I’ve downloaded the new .scriv (I said template before because I’d made a template from it!) so I’ll investigate the bibliography settings there. I’ll post if I still need help with it.

I added Typst tables to the recent template, using both Raw Typst block Style and Section Type examples. I’m not a huge fan of the Typst tables and prefer markdown tables, but currently the translation from Markdown to Typst tables is incomplete…

Regarding the Bibliography it is really easy. For Pandoc you use [@citekey] as you write, and you pass the path to your .bib file to the --bibliography parameter or add it to the metadata, and use --citeproc to activate the processing. If you want to put the bibliography in a section that is not the last one you can add this markdown as the only content of a section (in my template I use a Section Layout for this):

:::{#refs}

:::

The details are here: Pandoc - Pandoc User’s Guide

If you want Typst to do the Bibliography, you use @citekey as you write (similar enough to Pandoc but without the [ … ] and there are differences in how you assign prefix/suffix/locator, see Cite Function – Typst Documentation), then where you want the bibliography in the document add this raw Typst:

#bibliography("myrefs.bib", style: "apa")

In my template I use a Section Layout for this (the document itself is empty, the compiler adds this line), with an added tweak that I now specify the bibfile and bibstyle as custom metadata and this is passed as Scrivener placeholders, so you can just edit the metadata to change the citation style as an example.

1 Like

Yes, thank you. As I said, I’ve got the Raw Typst block style working as I need, but I’ve been doing something wrong in the Section Type with my own data. I haven’t had time to investigate further as things are very busy at the moment. I’m basically agnostic about type of table; that said, although the list-table.lua wayis straightforward to use, I haven’t found a way to control placement and row spacing, which I’ve got to grips with using raw typst, also the way raw typst tables code appears, it is much easier to scan than the list-table.lua version as it is compact while the same table in .lua can extentend over several screen heights. I’m not using mathematical formulae in them; I need to replicate what I can do in RTF with a couple of tabs with stops set appropriately.

I am continuing to work on the Pandoc > Typst route, as I do want the flexibility it provides. I will consult the Pandoc documentation, though again when I have the necessary peace and quiet. So far, with my lack of background, I have found such documentation quite hard to match up with what I can see, and for matters like this I’m never sure if I should be consulting the Scrivener manual, the MMD documentation, the Pandoc documentation or the Typst documentation, as I’m not sure at what point in the chain a given layout style or formatting etc. is implemented.

Anyway, with what you say here, I can set about editing the metadata line to my .bib file path and copy the bibliography style to the appropriate place for Pandoc. So I’ll see how I go.

:slight_smile:
Mark

… in §21.5.1 Compile Folder you cover the way to not make a folder on compilation for MMD (append -mmd for example) etc. — how can I get this to work for Plain Text outputs that also generate multiple files?

You can’t, sadly. It’s currently an open enhancement ticket though. We did take a look at it a cycle or two ago, and despite there already being code for this in place with MMD, it’s for some reason more complicated with TXT, so it was put off to a later date.

So for now you have to do this the old fashioned way, or the way Windows users did until v3 came out: drag the compiled material into the parent folder post-compile:

test.tex
├── 800px-LaTeX_logo.png
├── citations.bib
└── test.tex
    ├── 800px-LaTeX_logo.png
    └── test.tex

At least, this approach doesn’t delete what is in there (I presume you are getting that result because you are targeting the directory one up from this illustration, and thus wiping the support files every time unless they are locked). Although this does require an additional step, I’d be nervous about relying upon system locks sticking, and remembering to set them for new material, etc.

1 Like

For the Scrivener > Pandoc > Typst route, there are some problems if you want to use Typst native captioned figures / tables and cross-references. Typst uses e.g. <fig-label> to provide unique #ids for items like figures, and then to reference them you use e.g. @fig-label. Typst will know it is a figure and use the correct text (Figure 5: etc.). The problems are:

  1. Pandoc treats <...> as a raw HTML inline (RawInline), so it will be completely removed from the conversion to Typst. You could just disable the raw-html extension, but in fact we can make use of the RawInline tag in a Lua filter (see below)…
  2. Pandoc uses @citeid for bibliographic citations, and converts these for use with a bibliography and thus Typst cannot use them.

The good news is because both of these fragments are recognised by Pandoc, we can use a Lua filter to tweak the transformation.

  1. We can switch the raw format from HTML to typst, and thus <label> will now make its way through to output as required: https://github.com/iandol/dotpandoc/blob/master/filters/typstFix.lua#L17
  2. We can filter @cite so that if there is a fig-, tbl-, lst-, eq- or sec- prefix we convert the citation to a raw typst inline. Thus both real @citations and @cross-references will correctly make their way through: https://github.com/iandol/dotpandoc/blob/master/filters/typstFix.lua#L24

See the filter to do this here:




I recently used Typst for a Scrivener project utilising the wonderful lapreprint template; I now have a Pandoc template you can use in Scrivener if anyone is interested:

Compared to LaTeX, it is soooooo easy to tweak the template :heart_eyes: :heart_eyes: :heart_eyes:

5 Likes

Thanks Ian for this and for all the help you give here. I hope lots of academic Scrivenerati will find these useful and enjoy working with them. I’m certainly looking forward to trying it all out. I’ve been away for a few days, but will get down to it in the next few days.

:smiley:

Mark

Version 0.10 of Typst has been released:

Lots of small bugfixes, and performance has been made even faster. Compiling a paper to PDF now takes 2.3secs on my M2, LaTeX takes > 30secs on the same project!

3 Likes

Hello Ian,

I’ve been away from all this for some time, and unlikely to be able to get back to it for the next few weeks. However, I have downloaded this Lua filter and moved it into the appropriate directory; I presume that I need to add it to the processing pane with -L typstFix.lua.

Have a Happy Festive Season.

:smiley:

Mark

This filter fixes 3 things, that are not essential but can be helpful, unique labels for figures/tables/listings and their cross-references, and ensures figures that have no explicit width assigned are 100% width to the page margins.

I also have a scrivener post-processing script:

This runs instead of Pandoc in the post-processing pane, augmenting the paths and enabling some small fixes to the markdown (for example, you can put cross-reference labels at the start of your figure caption and it will move it to the correct place for Typst), it is a modified version of quarto-run.rb. It uses a Pandoc defaults file to configure Pandoc for Typst and runs Typst after the changes have been made etc.

1 Like

This is a new step for me; as it is a Ruby script, where should I put it in the environment? Can it just go into the Filters folder, along with the Lua scripts? And how do I modify the post-processing pane?

:smiley:
Mark

The Ruby script is a “runner”, its job is to replace pandoc/quarto/tpyst command in the post-processing pane. The main reason for this is that Scrivener runs commands in a highly restricted environment, where most other apps are not available. It is not essential to compilation, it is an optional helper. You don’t need it for Pandoc to compile to a Typst .typ file, but if you want Pandoc to generate a PDF from the .typ (where now Pandoc will need to know where Typst is) then Pandoc will not be able to find Typst and the runner script will solve that problem. Having a runner also gives us the option to do some pre-processing of the .md file before it goes to Pandoc, and also the .typ file before it goes to Typst (we can search and replace text, move things around).

The easiest way to use it is to copy it into the Script option of the compiler post-processing pane:

This is stored directly in the Scrivener project, no need to set up a path. Or, you can put it somewhere, anywhere really and then enter that path in the post-processing pane:

I have a ~/bin folder where I put scripts (~ means home on macOS and Linux, which resolves for me to /Users/ian/), but there is no requirement for it to be there. But for scripts to run they must be identified as executable, and sometimes on download they don’t get the executable set, so you can do this (Finder’s Get Info can set it, but lets use the Terminal):

chmod +x /Users/ian/bin/typst-run.rb

The final part of this puzzle is you can see the arguments are so simple, no filters, no options etc. How does Pandoc know what to do? Well in this case we pass a single entry typst-refs. This is the name of a Pandoc defaults file — a recipe of what we want Pandoc to do. These recipes can be anywhere on the path as long as you pass an absolute path, but Pandoc has a data directory where we can store our recipes. This is at ~/.local/share/pandoc in a defaults folder. So in the folder I put this file: https://github.com/iandol/dotpandoc/blob/master/defaults/typst-refs.yaml — the final path will be ~/.local/share/pandoc/defaults/typst-refs.yaml. Pandoc know where to look and so running -L typst-refs will resolve to that file. My script takes two parameters: (1) the name of the markdown file produced by Scrivener and (2) the name of a defaults file. We can the change the recipe and totally change the compilation.

The recipe does call a few other files, the filters (which Pandoc can find in ~/.local/share/pandoc/filters/), the bibliography and CSL (bibliography styles). CSL files can be stored in ~/.local/share/pandoc/csl/. I keep my main bibliography (well a copy) at ~/.local/share/pandoc/Core.json. The other files link to a template (template: custom.typst), you can remove it, or copy my templates to ~/.local/share/pandoc/templates.

Summary: start as simple as possible, and only when you are comfortable, build up the workflow.

1 Like