Run the Quarto CLI on the document you're editing. That's the whole plugin.
Its one real idea: a document can declare several output formats at once, so rendering is two actions, not one.
format:
html:
toc: true
pdf: default
docx: default<leader>rr builds html. <leader>ra builds all three. Everything is
buffer-local to the quarto filetype — in any other buffer the commands don't exist and
the mappings are unset.
Requires Neovim 0.10+ and the Quarto CLI. No Lua dependencies.
{ "matthewgson/quarto-render.nvim", ft = "quarto", opts = {} }setup() is optional — the defaults work untouched.
| Key | Action |
|---|---|
<leader>rr |
Render the first declared format |
<leader>ra |
Render all declared formats |
<leader>rf |
Pick a format, then render it |
<leader>rp |
Toggle the live preview |
<leader>rk |
Stop this buffer's jobs |
<leader>ro |
Open the output, or the live preview |
Buffer-local, so nothing outside a .qmd buffer changes. See
LazyVim for how these sit alongside the distro's own bindings.
Built and tested against the LazyVim distro, with defaults chosen to fit its conventions rather than fight them.
<leader>r is unclaimed by LazyVim core and by every lang.* extra. The one extra that
does claim it is editor.refactoring (+refactor, which includes rf and rp) — and
because these mappings are buffer-local, they shadow it only inside .qmd and leave it
untouched everywhere else.
Left alone on purpose:
<leader>c |
code — cf format, cr rename, cp markdown preview |
<leader>q |
quit / session |
<leader>a <leader>g <leader>G |
ai, git |
<localleader>, <CR> |
R.nvim, inside quarto buffers |
<C-Space> <C-h/j/k/l> <C-\> |
tmux navigation |
With the lang.r extra, R.nvim is already live in .qmd buffers: it owns <CR> for
sending lines to R, and a <localleader>q group labelled quarto whose bindings render
through your R session. Nothing here touches either, and this plugin's which-key group is
labelled quarto render so the two read differently at a glance. (<leader>cp markdown
preview is registered ft = "markdown", so it never applied to .qmd to begin with.)
Keep ft = "quarto" in the spec: the LazyVim starter sets defaults.lazy = false, so
without it this would load at startup.
| Command | |
|---|---|
:QuartoRender |
First declared format |
:QuartoRender all |
Every declared format |
:QuartoRender {format} |
A named format (completion offers what the document declares) |
:QuartoRenderPick |
Choose a format via vim.ui.select() |
:QuartoRenderPreview |
Toggle quarto preview — live reload on save |
:QuartoRenderStop |
Stop this buffer's jobs |
:QuartoRenderOpen |
Open the output, or the preview URL |
:QuartoRenderFormats |
Show detected formats and where they came from |
The QuartoRender prefix avoids shadowing quarto-nvim's global :QuartoPreview.
opts = {
quarto_cmd = "quarto",
render_args = {}, -- extra args per render, e.g. { "--no-clean" }
preview_args = {}, -- extra args per preview, e.g. { "--no-browser" }
save_before_render = true, -- quarto reads from disk
open_after_render = false, -- <leader>ro opens on demand regardless
verbosity = "normal", -- silent | errors | normal | verbose
keys = { -- `keys = false` disables all of them
group = "<leader>r", -- which-key group anchor; a label, not a prefix
render = "<leader>rr",
render_all = "<leader>ra",
render_pick = "<leader>rf",
preview = "<leader>rp",
stop = "<leader>rk",
open = "<leader>ro",
},
}Each value is a complete mapping, not a suffix, so overriding one leaves the others
alone; any single entry can be false.
Note
This keys table lives inside opts. It is not lazy.nvim's spec-level keys.
The front matter is scanned for a top-level format: key — scalar, flow sequence
([html, pdf]), block mapping, or block sequence. Only column-zero keys count, so nested
options and a format: under metadata: are ignored. Extension formats (acm-pdf) work.
Declaring nothing falls back to _quarto.yml, then to html; :QuartoRenderFormats says
which happened.
- Not a YAML parser: no anchors, aliases, or multi-line flow collections.
- Formats from
metadata-files:or--profilearen't detected, though:QuartoRender allstill renders them: it passes no--to. - Before the first render of a session,
:QuartoRenderOpenpredicts the output path and can't know about a projectoutput-dir:. Afterwards it uses what quarto reported.
This plugin renders documents — it doesn't run cells, complete inside them, or display images. For those: quarto-nvim, otter.nvim, R.nvim, molten-nvim. They coexist with this one.
nvim --headless -u NONE -i NONE -l tests/run.lua # tests
stylua --check .
vhs assets/demo.tape # re-record the demoMIT
