While switching from VSCode to the vim-inspired Helix text editor this summer provided much perceived efficiency and fun, it also degraded my editing workflow for Typst—the LaTeX replacement with markdown-like syntax—by making previewing less ergonomic. After much finnicking, I’ve found a satisfactory Helix configuration on par with VSCode’s functionality.

What you get

Screenshot of working Typst preview, with two terminals with Typst files open in Helix next to their preview windows.

This configuration creates two new keyboard shortcuts you can use when editing Typst files:

KeybindingAction
ctrl+shift+pOpen a previewing window
ctrl+pSet the file the preview window previews to the currently open buffer

The previewing window

  • Has all the preview features for the Typst language server Tinymist, including instant previewing as you type, jumping to source on-click, and dark theme
  • Spawns as a seperate window without distracting browser elements like tabs and search bars
  • Works without conflicting with other preview windows spawned from other Helix instances

Configuration steps

  1. Make sure you’ve installed the Typst language server Tinymist
  2. Open your global Helix languages file, and append:

    languages.toml
    [language-server.tinymist]
    command = "tinymist"
    config.preview.background.enabled = true
    config.preview.background.args = ["--data-plane-host=127.0.0.1:0"]

    These lines configure Tinymist to start a preview server at a random port once you’ve opened your first Typst file, as specified by setting the data-plane-host port to 0.

  3. Make sure you’ve installed Nushell—a modern shell and programming language intended to replace bash, zsh, and other shells—so that you can run the preview-opening script.1
  4. Create a file typst-preview.nu somewhere, perhaps in your Helix config directory, with the contents:

    typst-preview.nu
    let helix_pid = (ps | where pid == $nu.pid | first).ppid
    
    let tinymist_proc = ps
    | where ppid == $helix_pid
    | where name =~ tinymist
    | first
    if $tinymist_proc == null {
        print "tinymist proc is null"
    } else {
        let tinymist_entry = lsof -i -P -n
        | from ssv --minimum-spaces 1
        | where PID == ($tinymist_proc.pid |
        into string)
        | first
        # should be `google-chrome --app=("http://" + $tinymist_entry.NAME)` on Linux
        ^open -na "Google Chrome" --args --app=("http://" + $tinymist_entry.NAME)
    }

    This script finds your Helix instance’s process ID, finds the child Tinymist process that the Helix instance spawned, and looks up the address of the previewing server based on the child’s process ID.

    The final open command opens the address in Chrome, using the --app flag of Chromium browsers to hide tabs and other superfluous UI elements.2

  5. Open your Helix config file, and append:
    config.toml
    [keys.normal]
    "C-S-p" = ':sh nu ~/.config/helix/typst-preview.nu'
    "C-p" = ':lsp-workspace-command tinymist.pinMain "%sh{realpath %{buffer_name}}"'
    These lines create the keyboard shortcuts described above.

Credits

Most of the config comes from sijo’s reply in the Typst forums, without which I wouldn’t have understood how to make Tinymist preview at a random port. Thank you!

My improvements consist of

  • Letting you open the preview server intentionally with a shortcut instead of having Tinymist open your browser automatically on startup and annoyingly steal your focus
  • Opening the preview in a dedicated UI-less window instead of cluttering your browser’s tabs3

I hope this helps!

  1. If you don’t like installing things, you can also rewrite the script in Bash and update the Helix command to run the Bash script. ↩︎
  2. You can also open the url in other browsers like Firefox or Safari, but to my knowledge those browsers don’t have a similar UI-hiding feature. ↩︎
  3. Additionally, because I use Zen as my actual browser, opening the preview in the seperate app Chrome allow any shortcuts I use to switch to the Zen app to better match my intent, focusing my actual browser window instead of a random Typst preview. ↩︎