Editor support and syntax highlighting

.qvr files are highlighted by two complementary systems, depending on what reads the file:

Consumer Engine Comes from
Python tools: mkdocs, Sphinx, Jupyter, IPython, pygmentize Pygments bundled with the quivers PyPI package
Editors: Neovim, Helix, Emacs, Zed, VS Code (via tree-sitter extension) tree-sitter bundled with panproto-grammars-all and the in-tree grammars/qvr/ source
GitHub.com source view, GitHub gists Linguist language registration (not yet upstream)

This page documents how to wire each one up.

Pygments (Python doc and notebook tools)

Quivers ships a Pygments lexer registered as an entry point. After

pip install quivers

every Pygments-based tool finds .qvr files automatically. No further configuration is needed for mkdocs, Sphinx, pygmentize, IPython / Jupyter cell magic (%%highlight qvr), GitHub Gists rendered via Pygments locally, or any other consumer that asks Pygments to choose a lexer by filename or by name="qvr".

To confirm the lexer is visible:

python -c "from pygments.lexers import get_lexer_by_name; print(get_lexer_by_name('qvr').name)"
# QVR

To highlight a file to a terminal:

pygmentize -l qvr -O style=monokai docs/examples/source/bayesian_regression.qvr

The lexer source lives at src/quivers/dsl/pygments_lexer.py; the highlight rules and keyword list are kept in sync with the tree-sitter grammar by tests/test_dsl_extensions.py.

Tree-sitter (editors)

The tree-sitter grammar lives at grammars/qvr/ in the quivers repository and is vendored by the panproto-grammars-all distribution. Most editor integrations consume the grammar through one of two paths:

  1. The vendored parser.c inside panproto-grammars-all.
  2. A direct clone of the quivers repo with a per-editor build step against grammars/qvr/.

The Neovim, Helix, Emacs, and Zed instructions below cover (2). The grammar follows standard tree-sitter conventions; if your editor has a :TSInstall qvr or equivalent command and the grammar isn't on the upstream list yet, the manual paths below also work.

Neovim

With nvim-treesitter:

-- init.lua  (or any config file loaded after nvim-treesitter)
local parsers = require("nvim-treesitter.parsers").get_parser_configs()
parsers.qvr = {
  install_info = {
    url = "https://github.com/FACTSlab/quivers",
    files = { "grammars/qvr/src/parser.c" },
    location = "grammars/qvr",
    branch = "main",
    generate_requires_npm = false,
    requires_generate_from_grammar = false,
  },
  filetype = "qvr",
}
vim.filetype.add({ extension = { qvr = "qvr" } })

Then :TSInstall qvr from inside Neovim. The repository ships queries/highlights.scm at grammars/qvr/queries/highlights.scm; nvim-treesitter picks it up automatically once the parser is registered.

Helix

Helix has native tree-sitter support. Add to ~/.config/helix/languages.toml:

[[language]]
name = "qvr"
scope = "source.qvr"
file-types = ["qvr"]
roots = []
comment-token = "#"
indent = { tab-width = 4, unit = "    " }

[[grammar]]
name = "qvr"
source = { git = "https://github.com/FACTSlab/quivers", subpath = "grammars/qvr" }

Then:

hx --grammar fetch
hx --grammar build

Place the highlight queries at ~/.config/helix/runtime/queries/qvr/highlights.scm; copy the file from grammars/qvr/queries/highlights.scm in this repository, or symlink to a checkout.

Emacs (tree-sitter-langs)

With tree-sitter-langs and built-in treesit (Emacs 29+):

(add-to-list 'treesit-language-source-alist
             '(qvr . ("https://github.com/FACTSlab/quivers"
                      "main"  ; branch
                      "grammars/qvr/src")))
(define-derived-mode qvr-mode prog-mode "QVR"
  "Major mode for editing .qvr files."
  (when (treesit-ready-p 'qvr)
    (treesit-parser-create 'qvr)
    (setq-local treesit-font-lock-settings
                (treesit-font-lock-rules
                 :language 'qvr
                 :feature 'comment
                 '((comment) @font-lock-comment-face)
                 :language 'qvr
                 :feature 'keyword
                 '(["morphism" "object" "program"
                    "composition" "category" "contraction" "bundle"
                    "deduction" "atoms" "start" "depth"
                    "lexicon" "let" "in" "sample" "observe"
                    "marginalize" "return" "factor" "score"
                    "export" "as" "over"
                    "algebra" "semigroupoid" "bilinear_form"
                    "rule"]
                   @font-lock-keyword-face)))
    (treesit-major-mode-setup)))
(add-to-list 'auto-mode-alist '("\\.qvr\\'" . qvr-mode))

Run M-x treesit-install-language-grammar RET qvr RET once after Emacs starts to fetch the parser.

Zed

The quivers repository ships a Zed extension at editors/zed-extension-qvr/. Until the extension is published to Zed's public registry, install it locally from a checkout:

git clone https://github.com/FACTSlab/quivers
mkdir -p ~/.config/zed/extensions
ln -s "$(pwd)/quivers/editors/zed-extension-qvr" ~/.config/zed/extensions/qvr

Reload extensions (zed: reload extensions from the command palette). The extension's manifest pins the grammar against grammars/qvr/ in the same repository, so a single checkout drives both the grammar source and the editor packaging.

VS Code / Cursor

The repository ships a first-party VS Code extension at editors/vscode-qvr/. It provides:

  • a TextMate grammar for the initial render,
  • a vscode-languageclient bridge to qvr-lsp for hover, go-to-definition, semantic tokens, document symbols, completion, formatting, and live diagnostics.

Install the packaged extension into VS Code (or Cursor):

cd editors/vscode-qvr
npm install
npx tsc -p .
npx @vscode/vsce package --allow-missing-repository --no-yarn
code --install-extension vscode-qvr-*.vsix
# or: cursor --install-extension vscode-qvr-*.vsix

The extension auto-discovers qvr-lsp in (1) the qvr.lsp.path setting (with ${workspaceFolder} expansion), (2) <workspace>/.venv/bin/qvr-lsp, (3) $VIRTUAL_ENV/bin/qvr-lsp, or (4) plain qvr-lsp on $PATH. Install the LSP extra with pip install 'quivers[lsp]'.

The full configuration surface and the launch resolution order live in the Interactive guide.

GitHub source view (Linguist)

GitHub's syntax highlighting on .qvr files in repository source view and gists is driven by github-linguist. QVR is not yet upstream; until the language is registered, repositories can override locally with a .gitattributes entry pointing at the closest existing language for at least some color:

*.qvr linguist-language=Haskell

Haskell is the closest match for <-, let, >>=, the offside-rule program-block bodies, and the |-separated rule head / body shape; it is not perfect (the categorial slash, the ~ Family clause, and the axis-role surface get no special treatment), but is the closest readily-available approximation.

Registering QVR upstream with Linguist is tracked at panproto/panproto#84; upvoting helps prioritize it.

Verifying your setup

A short check that exercises every distinguishing surface feature:

object D : FinSet 32
object K : FinSet 64
object SD : Real 32
object SK : Real 64

morphism W : SD -> SK [role=latent, over=[dom, cod]] ~ MatrixNormal(0.0, 1.0)
morphism softmax_link : SK -> SK [role=kernel, scale=0.1] ~ Normal
program regression : SD -> SK [effects = [Sample, Score]]
    let z = W >> softmax_link
    observe y : K <- Normal(z, 0.5)
    return y

export regression

When the highlighting is wired up, keywords (object, morphism, program, let, observe, return, export), the option-block keys and the family-init sigil (role=, over=, effects=, ~), the <- Kleisli-bind punctuation, the family identifiers (MatrixNormal, Normal), and the comments (none here, but #-prefixed lines anywhere in the file) all carry distinct colors.

If a token is unhighlighted (rendered as default-foreground text), the corresponding rule in the editor's highlight query is the place to look; the canonical reference is grammars/qvr/queries/highlights.scm.