From c8e3a88434bfa7800d9d48cea39fdbc86c3da94d Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 16:33:58 -0500
Subject: [PATCH 01/12] fix: stream stderr for long-running providers, clear
errors on success (#40)
Problem: Long-running providers (e.g. `typst watch`) never exit on
compile error, so the exit callback never fired and diagnostics/quickfix
were never populated. The `typst watch` `reload` command also lacked
`--diagnostic-format short`, producing unparseable verbose output.
Solution: Add a `stderr` streaming callback to the long-running
`vim.system` call that accumulates chunks and re-parses on each new
chunk, populating diagnostics or quickfix in real time. When the
fs_event fires (successful compile), clear `stderr_acc` and the
reported errors. Add `--diagnostic-format short` to the typst `reload`
command to match the one-shot `args` format.
---
lua/preview/compiler.lua | 43 ++++++++++++++++++++++++++++++++++++++++
lua/preview/presets.lua | 2 +-
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua
index c5a81c2..3f897ad 100644
--- a/lua/preview/compiler.lua
+++ b/lua/preview/compiler.lua
@@ -143,12 +143,45 @@ function M.compile(bufnr, name, provider, ctx, opts)
table.concat(reload_cmd, ' ')
)
+ local stderr_acc = {}
local obj
obj = vim.system(
reload_cmd,
{
cwd = cwd,
env = provider.env,
+ stderr = vim.schedule_wrap(function(err, data)
+ if not data or not vim.api.nvim_buf_is_valid(bufnr) then
+ return
+ end
+ stderr_acc[#stderr_acc + 1] = data
+ local errors_mode = provider.errors
+ if errors_mode == nil then
+ errors_mode = 'diagnostic'
+ end
+ if provider.error_parser and errors_mode then
+ local output = table.concat(stderr_acc)
+ if errors_mode == 'diagnostic' then
+ diagnostic.set(bufnr, name, provider.error_parser, output, ctx)
+ elseif errors_mode == 'quickfix' then
+ local ok, diags = pcall(provider.error_parser, output, ctx)
+ if ok and diags and #diags > 0 then
+ local items = {}
+ for _, d in ipairs(diags) do
+ table.insert(items, {
+ bufnr = bufnr,
+ lnum = d.lnum + 1,
+ col = d.col + 1,
+ text = d.message,
+ type = d.severity == vim.diagnostic.severity.WARN and 'W' or 'E',
+ })
+ end
+ vim.fn.setqflist(items, 'r')
+ vim.cmd('copen')
+ end
+ end
+ end
+ end),
},
vim.schedule_wrap(function(result)
if active[bufnr] and active[bufnr].obj == obj then
@@ -228,6 +261,16 @@ function M.compile(bufnr, name, provider, ctx, opts)
return
end
stop_open_watcher(bufnr)
+ stderr_acc = {}
+ local errors_mode = provider.errors
+ if errors_mode == nil then
+ errors_mode = 'diagnostic'
+ end
+ if errors_mode == 'diagnostic' then
+ diagnostic.clear(bufnr)
+ elseif errors_mode == 'quickfix' then
+ vim.fn.setqflist({}, 'r')
+ end
do_open(bufnr, output_file, provider.open)
opened[bufnr] = true
end)
diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua
index f189e98..3591a21 100644
--- a/lua/preview/presets.lua
+++ b/lua/preview/presets.lua
@@ -133,7 +133,7 @@ M.typst = {
end,
open = true,
reload = function(ctx)
- return { 'typst', 'watch', ctx.file }
+ return { 'typst', 'watch', '--diagnostic-format', 'short', ctx.file }
end,
}
From 3e6ba580e4e3c8dc544c0994659757ed12066c3f Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 17:23:06 -0500
Subject: [PATCH 02/12] fix: quickfix support for long-running providers (#41)
* fix(compiler): open quickfix in background, retain focus on source buffer
* fix(compiler): use cwindow and win_gotoid for quickfix focus management
* fix: unused var warning and update typst reload test for short format
* fix: remove testing files
---
README.html | 963 ---------------------------------------
README.md | 4 +-
lua/preview/compiler.lua | 16 +-
spec/presets_spec.lua | 4 +-
4 files changed, 17 insertions(+), 970 deletions(-)
delete mode 100644 README.html
diff --git a/README.html b/README.html
deleted file mode 100644
index b6600fc..0000000
--- a/README.html
+++ /dev/null
@@ -1,963 +0,0 @@
-
-
-
-
-
-
- README
-
-
-
-
-preview.nvim
-Universal document previewer for Neovim
-An extensible framework for compiling and previewing any
-documents (LaTeX, Typst, Markdown, etc.)—diagnostics included.
-Features
-
-- Async compilation via
vim.system()
-- Built-in presets for Typst, LaTeX (latexmk, pdflatex, tectonic),
-Markdown, GitHub-flavored Markdown, AsciiDoc, and Quarto
-- Compiler errors as native
vim.diagnostic
-- User events for extensibility (
PreviewCompileStarted,
-PreviewCompileSuccess,
-PreviewCompileFailed)
-
-Requirements
-
-Installation
-Install with your package manager of choice or via luarocks:
-luarocks install preview.nvim
-Documentation
-:help preview.nvim
-FAQ
-Q: How do I define a custom provider?
-require('preview').setup({
- rst = {
- cmd = { 'rst2html' },
- args = function(ctx)
- return { ctx.file, ctx.output }
- end,
- output = function(ctx)
- return ctx.file:gsub('%.rst$', '.html')
- end,
- },
-})
-Q: How do I override a preset?
-require('preview').setup({
- typst = { env = { TYPST_FONT_PATHS = '/usr/share/fonts' } },
-})
-Q: How do I automatically open the output file?
-Set open = true on your provider (all built-in presets
-have this enabled) to open the output with vim.ui.open()
-after the first successful compilation in toggle/watch mode. For a
-specific application, pass a command table:
-require('preview').setup({
- typst = { open = { 'sioyek', '--new-instance' } },
-})
-
-
-
diff --git a/README.md b/README.md
index 286e1ac..18bc192 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
**Universal document previewer for Neovim**
-An extensible framework for compiling and previewing *any* documents (LaTeX, Typst,
-Markdown, etc.)—diagnostics included.
+An extensible framework for compiling and previewing _any_ documents (LaTeX,
+Typst, Markdown, etc.)—diagnostics included.
## Features
diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua
index 3f897ad..a3b9c47 100644
--- a/lua/preview/compiler.lua
+++ b/lua/preview/compiler.lua
@@ -150,7 +150,7 @@ function M.compile(bufnr, name, provider, ctx, opts)
{
cwd = cwd,
env = provider.env,
- stderr = vim.schedule_wrap(function(err, data)
+ stderr = vim.schedule_wrap(function(_err, data)
if not data or not vim.api.nvim_buf_is_valid(bufnr) then
return
end
@@ -177,7 +177,9 @@ function M.compile(bufnr, name, provider, ctx, opts)
})
end
vim.fn.setqflist(items, 'r')
- vim.cmd('copen')
+ local win = vim.fn.win_getid()
+ vim.cmd.cwindow()
+ vim.fn.win_gotoid(win)
end
end
end
@@ -215,7 +217,9 @@ function M.compile(bufnr, name, provider, ctx, opts)
})
end
vim.fn.setqflist(items, 'r')
- vim.cmd('copen')
+ local win = vim.fn.win_getid()
+ vim.cmd.cwindow()
+ vim.fn.win_gotoid(win)
end
end
end
@@ -270,6 +274,7 @@ function M.compile(bufnr, name, provider, ctx, opts)
diagnostic.clear(bufnr)
elseif errors_mode == 'quickfix' then
vim.fn.setqflist({}, 'r')
+ vim.cmd.cwindow()
end
do_open(bufnr, output_file, provider.open)
opened[bufnr] = true
@@ -331,6 +336,7 @@ function M.compile(bufnr, name, provider, ctx, opts)
diagnostic.clear(bufnr)
elseif errors_mode == 'quickfix' then
vim.fn.setqflist({}, 'r')
+ vim.cmd.cwindow()
end
vim.api.nvim_exec_autocmds('User', {
pattern = 'PreviewCompileSuccess',
@@ -372,7 +378,9 @@ function M.compile(bufnr, name, provider, ctx, opts)
})
end
vim.fn.setqflist(items, 'r')
- vim.cmd('copen')
+ local win = vim.fn.win_getid()
+ vim.cmd.cwindow()
+ vim.fn.win_gotoid(win)
end
end
end
diff --git a/spec/presets_spec.lua b/spec/presets_spec.lua
index 2a63d18..2160dfa 100644
--- a/spec/presets_spec.lua
+++ b/spec/presets_spec.lua
@@ -50,7 +50,9 @@ describe('presets', function()
assert.is_table(result)
assert.are.equal('typst', result[1])
assert.are.equal('watch', result[2])
- assert.are.equal(ctx.file, result[3])
+ assert.are.equal('--diagnostic-format', result[3])
+ assert.are.equal('short', result[4])
+ assert.are.equal(ctx.file, result[5])
end)
it('parses errors from stderr', function()
From cf8fd02e6d844f203ef958e24c75656ca4ba20d3 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 17:23:57 -0500
Subject: [PATCH 03/12] Add video demonstration to README
Added a video demonstration to the README.
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 18bc192..8e0f56f 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@
An extensible framework for compiling and previewing _any_ documents (LaTeX,
Typst, Markdown, etc.)—diagnostics included.
+
+
## Features
- Async compilation via `vim.system()`
From 8107f8c0acd616d3d315c2d25e1b1179de554f0a Mon Sep 17 00:00:00 2001
From: Barrett Ruth
Date: Wed, 4 Mar 2026 17:28:07 -0500
Subject: [PATCH 04/12] doc: improve error phrasing, remove redundant feautre
---
README.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 8e0f56f..aa9dd91 100644
--- a/README.md
+++ b/README.md
@@ -12,9 +12,7 @@ Typst, Markdown, etc.)—diagnostics included.
- Async compilation via `vim.system()`
- Built-in presets for Typst, LaTeX (latexmk, pdflatex, tectonic), Markdown,
GitHub-flavored Markdown, AsciiDoc, and Quarto
-- Compiler errors as native `vim.diagnostic`
-- User events for extensibility (`PreviewCompileStarted`,
- `PreviewCompileSuccess`, `PreviewCompileFailed`)
+- Compiler errors via `vim.diagnostic` or quickfix
## Requirements
From bb9ca987e10883ecb89a84feac5f1e32ba5a7bd8 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:12:33 -0500
Subject: [PATCH 05/12] Add note about previewer auto-close feature
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index aa9dd91..4160267 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ Typst, Markdown, etc.)—diagnostics included.
- Built-in presets for Typst, LaTeX (latexmk, pdflatex, tectonic), Markdown,
GitHub-flavored Markdown, AsciiDoc, and Quarto
- Compiler errors via `vim.diagnostic` or quickfix
+- Previewer auto-close on buffer deletion
## Requirements
From f1aed82f4251215b0927b607e30d2358ac3d4231 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:30:56 -0500
Subject: [PATCH 06/12] feat: add `detach` provider field and `vim.g.preview`
config support (#42)
Problem: viewer processes launched via a string[] `open` command were
always killed on buffer deletion with no way to opt out. Configuring
the plugin also required an explicit `setup()` call in a `config`
hook, preventing config from being declared before the plugin loads.
Solution: add a `detach` boolean to `ProviderConfig` that skips
SIGTERM on buffer unload. Auto-call `setup()` from `vim.g.preview`
at module load time, enabling config via lazy.nvim's `init` hook.
Update vimdoc and README accordingly.
---
README.md | 14 ++++++++++++--
doc/preview.nvim.txt | 15 +++++++++++++--
lua/preview/compiler.lua | 12 +++++++++---
lua/preview/init.lua | 6 ++++++
4 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 4160267..3bbb203 100644
--- a/README.md
+++ b/README.md
@@ -21,8 +21,18 @@ Typst, Markdown, etc.)—diagnostics included.
## Installation
-Install with your package manager of choice or via
-[luarocks](https://luarocks.org/modules/barrettruth/preview.nvim):
+With lazy.nvim:
+
+```lua
+{
+ 'barrettruth/preview.nvim',
+ init = function()
+ vim.g.preview = { typst = true, latex = true }
+ end,
+}
+```
+
+Or via [luarocks](https://luarocks.org/modules/barrettruth/preview.nvim):
```
luarocks install preview.nvim
diff --git a/doc/preview.nvim.txt b/doc/preview.nvim.txt
index e2747d6..c64db62 100644
--- a/doc/preview.nvim.txt
+++ b/doc/preview.nvim.txt
@@ -23,12 +23,17 @@ REQUIREMENTS *preview.nvim-requirements
==============================================================================
SETUP *preview.nvim-setup*
-Load preview.nvim with your package manager. For example, with lazy.nvim: >lua
+With lazy.nvim, set |vim.g.preview| in `init` so configuration is applied
+before the plugin loads: >lua
{
'barrettruth/preview.nvim',
+ init = function()
+ vim.g.preview = { typst = true, latex = true }
+ end,
}
<
-Call |preview.setup()| to configure providers before use.
+Alternatively, call |preview.setup()| directly in a `config` function or
+anywhere the plugin is already loaded.
==============================================================================
CONFIGURATION *preview.nvim-configuration*
@@ -108,6 +113,12 @@ Provider fields:~
|preview.Context| and returns a
string[].
+ `detach` boolean When `true`, the viewer process opened
+ via a string[] `open` command is not
+ sent SIGTERM when the buffer is deleted.
+ Has no effect when `open` is `true`.
+ Default: `false`.
+
*preview.Context*
Context fields:~
diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua
index a3b9c47..a193ad2 100644
--- a/lua/preview/compiler.lua
+++ b/lua/preview/compiler.lua
@@ -291,7 +291,9 @@ function M.compile(bufnr, name, provider, ctx, opts)
callback = function()
M.stop(bufnr)
stop_open_watcher(bufnr)
- close_viewer(bufnr)
+ if not provider.detach then
+ close_viewer(bufnr)
+ end
last_output[bufnr] = nil
end,
})
@@ -404,7 +406,9 @@ function M.compile(bufnr, name, provider, ctx, opts)
once = true,
callback = function()
M.stop(bufnr)
- close_viewer(bufnr)
+ if not provider.detach then
+ close_viewer(bufnr)
+ end
last_output[bufnr] = nil
end,
})
@@ -507,7 +511,9 @@ function M.toggle(bufnr, name, provider, ctx_builder)
callback = function()
M.unwatch(bufnr)
stop_open_watcher(bufnr)
- close_viewer(bufnr)
+ if not provider.detach then
+ close_viewer(bufnr)
+ end
opened[bufnr] = nil
end,
})
diff --git a/lua/preview/init.lua b/lua/preview/init.lua
index fd54d71..322b893 100644
--- a/lua/preview/init.lua
+++ b/lua/preview/init.lua
@@ -10,6 +10,7 @@
---@field clean? string[]|fun(ctx: preview.Context): string[]
---@field open? boolean|string[]
---@field reload? boolean|string[]|fun(ctx: preview.Context): string[]
+---@field detach? boolean
---@class preview.Config
---@field debug boolean|string
@@ -101,6 +102,7 @@ function M.setup(opts)
end, 'false, "diagnostic", or "quickfix"')
vim.validate(prefix .. '.open', provider.open, { 'boolean', 'table' }, true)
vim.validate(prefix .. '.reload', provider.reload, { 'boolean', 'table', 'function' }, true)
+ vim.validate(prefix .. '.detach', provider.detach, 'boolean', true)
end
config = vim.tbl_deep_extend('force', default_config, {
@@ -246,4 +248,8 @@ M._test = {
end,
}
+if vim.g.preview then
+ M.setup(vim.g.preview)
+end
+
return M
From 7895b67c21d9cabcf9a3ff3bfb107754027127fa Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:39:00 -0500
Subject: [PATCH 07/12] docs: replace all `setup()` references with
`vim.g.preview` (#43)
---
README.md | 12 ++++++------
doc/preview.nvim.txt | 34 +++++++++++++---------------------
2 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/README.md b/README.md
index 3bbb203..3ffbc38 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ luarocks install preview.nvim
**Q: How do I define a custom provider?**
```lua
-require('preview').setup({
+vim.g.preview = {
rst = {
cmd = { 'rst2html' },
args = function(ctx)
@@ -59,15 +59,15 @@ require('preview').setup({
return ctx.file:gsub('%.rst$', '.html')
end,
},
-})
+}
```
**Q: How do I override a preset?**
```lua
-require('preview').setup({
+vim.g.preview = {
typst = { env = { TYPST_FONT_PATHS = '/usr/share/fonts' } },
-})
+}
```
**Q: How do I automatically open the output file?**
@@ -77,7 +77,7 @@ open the output with `vim.ui.open()` after the first successful compilation in
toggle/watch mode. For a specific application, pass a command table:
```lua
-require('preview').setup({
+vim.g.preview = {
typst = { open = { 'sioyek', '--new-instance' } },
-})
+}
```
diff --git a/doc/preview.nvim.txt b/doc/preview.nvim.txt
index c64db62..2566301 100644
--- a/doc/preview.nvim.txt
+++ b/doc/preview.nvim.txt
@@ -23,8 +23,7 @@ REQUIREMENTS *preview.nvim-requirements
==============================================================================
SETUP *preview.nvim-setup*
-With lazy.nvim, set |vim.g.preview| in `init` so configuration is applied
-before the plugin loads: >lua
+Set |vim.g.preview| before the plugin loads: >lua
{
'barrettruth/preview.nvim',
init = function()
@@ -32,19 +31,12 @@ before the plugin loads: >lua
end,
}
<
-Alternatively, call |preview.setup()| directly in a `config` function or
-anywhere the plugin is already loaded.
==============================================================================
CONFIGURATION *preview.nvim-configuration*
-Configure via `require('preview').setup()`.
-
- *preview.setup()*
-setup({opts?})
-
- `opts` is a table where keys are preset names or filetypes. For each
- key `k` with value `v` (excluding `debug`):
+Configure by setting |vim.g.preview| to a table where keys are preset names
+or filetypes. For each key `k` with value `v` (excluding `debug`):
- If `k` is a preset name and `v` is `true`, the preset is registered
as-is under its filetype.
@@ -131,30 +123,30 @@ Context fields:~
Example enabling presets:~
>lua
- require('preview').setup({ typst = true, latex = true, github = true })
+ vim.g.preview = { typst = true, latex = true, github = true }
<
Example overriding a preset field:~
>lua
- require('preview').setup({
+ vim.g.preview = {
typst = { open = { 'sioyek', '--new-instance' } },
- })
+ }
<
Example overriding the output path (e.g. latexmk `$out_dir`):~
>lua
- require('preview').setup({
+ vim.g.preview = {
latex = {
output = function(ctx)
return 'build/' .. vim.fn.fnamemodify(ctx.file, ':t:r') .. '.pdf'
end,
},
- })
+ }
<
Example with a fully custom provider (key is not a preset name):~
>lua
- require('preview').setup({
+ vim.g.preview = {
rst = {
cmd = { 'rst2html' },
args = function(ctx)
@@ -164,7 +156,7 @@ Example with a fully custom provider (key is not a preset name):~
return ctx.file:gsub('%.rst$', '.html')
end,
},
- })
+ }
<
==============================================================================
@@ -184,14 +176,14 @@ Import them from `preview.presets`:
Enable presets with `preset_name = true`:
>lua
- require('preview').setup({ typst = true, latex = true, github = true })
+ vim.g.preview = { typst = true, latex = true, github = true }
<
Override individual fields by passing a table instead of `true`:
>lua
- require('preview').setup({
+ vim.g.preview = {
typst = { env = { TYPST_FONT_PATHS = '/usr/share/fonts' } },
- })
+ }
<
==============================================================================
From 837c97cd09540d34d52afd035bdcd4b641fb1c21 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Thu, 5 Mar 2026 01:38:29 -0500
Subject: [PATCH 08/12] docs: rewrite vimdoc to match `pending.txt` conventions
(#44)
Problem: The vimdoc used `preview.nvim.txt` filename and
`*preview.nvim-xyz*` tags, inconsistent with other plugins.
Solution: Rename to `preview.txt`, normalize tags to `*preview-xyz*`,
add contents/install sections, and use `{field} (type)` formatting.
---
doc/preview.nvim.txt | 277 -------------------------------------------
doc/preview.txt | 274 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 274 insertions(+), 277 deletions(-)
delete mode 100644 doc/preview.nvim.txt
create mode 100644 doc/preview.txt
diff --git a/doc/preview.nvim.txt b/doc/preview.nvim.txt
deleted file mode 100644
index 2566301..0000000
--- a/doc/preview.nvim.txt
+++ /dev/null
@@ -1,277 +0,0 @@
-*preview.nvim.txt* Async document compilation for Neovim
-
-Author: Barrett Ruth
-License: MIT
-
-==============================================================================
-INTRODUCTION *preview.nvim*
-
-preview.nvim is an extensible framework for compiling documents asynchronously
-in Neovim. It provides a unified interface for any compilation workflow —
-LaTeX, Typst, Markdown, or anything else with a CLI compiler.
-
-The plugin ships with opt-in presets for common tools (Typst, LaTeX, Pandoc,
-AsciiDoc, Quarto) and supports fully custom providers.
-See |preview.nvim-presets|.
-
-==============================================================================
-REQUIREMENTS *preview.nvim-requirements*
-
-- Neovim >= 0.11.0
-- A compiler binary for each configured provider (e.g. `typst`, `latexmk`)
-
-==============================================================================
-SETUP *preview.nvim-setup*
-
-Set |vim.g.preview| before the plugin loads: >lua
- {
- 'barrettruth/preview.nvim',
- init = function()
- vim.g.preview = { typst = true, latex = true }
- end,
- }
-<
-
-==============================================================================
-CONFIGURATION *preview.nvim-configuration*
-
-Configure by setting |vim.g.preview| to a table where keys are preset names
-or filetypes. For each key `k` with value `v` (excluding `debug`):
-
- - If `k` is a preset name and `v` is `true`, the preset is registered
- as-is under its filetype.
- - If `k` is a preset name and `v` is a table, it is deep-merged with
- the preset and registered under the preset's filetype.
- - If `k` is not a preset name and `v` is a table, it is registered
- directly as a custom provider keyed by filetype `k`.
- - If `v` is `false`, the entry is skipped (no-op).
-
- See |preview.nvim-presets| for available preset names.
-
- Fields:~
-
- `debug` boolean|string Enable debug logging. A string value
- is treated as a log file path.
- Default: `false`
-
- *preview.ProviderConfig*
-Provider fields:~
-
- `cmd` string[] The compiler command (required).
-
- `args` string[]|function Additional arguments. If a function,
- receives a |preview.Context| and returns
- a string[].
-
- `cwd` string|function Working directory. If a function,
- receives a |preview.Context|. Default:
- git root or file directory.
-
- `env` table Environment variables.
-
- `output` string|function Output file path. If a function,
- receives a |preview.Context|.
-
- `error_parser` function Receives (output, |preview.Context|)
- and returns vim.Diagnostic[].
-
- `errors` false|'diagnostic'|'quickfix'
- How parse errors are reported.
- `false` suppresses error handling.
- `'quickfix'` populates the quickfix
- list and opens it. Default:
- `'diagnostic'`.
-
- `clean` string[]|function Command to remove build artifacts.
- If a function, receives a
- |preview.Context|.
-
- `open` boolean|string[] Open the output file after the first
- successful compilation in toggle/watch
- mode. `true` uses |vim.ui.open()|. A
- string[] is run as a command with the
- output path appended. When a string[]
- is used the viewer process is tracked
- and sent SIGTERM when the buffer is
- deleted. `true` and single-instance
- apps (e.g. Chrome) do not support
- auto-close.
-
- `reload` boolean|string[]|function
- Reload the output after recompilation.
- `true` uses a built-in SSE server for
- HTML files. A string[] is run as a
- command. If a function, receives a
- |preview.Context| and returns a
- string[].
-
- `detach` boolean When `true`, the viewer process opened
- via a string[] `open` command is not
- sent SIGTERM when the buffer is deleted.
- Has no effect when `open` is `true`.
- Default: `false`.
-
- *preview.Context*
-Context fields:~
-
- `bufnr` integer Buffer number.
- `file` string Absolute file path.
- `root` string Project root (git root or file directory).
- `ft` string Filetype.
- `output` string? Resolved output file path (set after `output`
- is evaluated, available to `args` functions).
-
-Example enabling presets:~
->lua
- vim.g.preview = { typst = true, latex = true, github = true }
-<
-
-Example overriding a preset field:~
->lua
- vim.g.preview = {
- typst = { open = { 'sioyek', '--new-instance' } },
- }
-<
-
-Example overriding the output path (e.g. latexmk `$out_dir`):~
->lua
- vim.g.preview = {
- latex = {
- output = function(ctx)
- return 'build/' .. vim.fn.fnamemodify(ctx.file, ':t:r') .. '.pdf'
- end,
- },
- }
-<
-
-Example with a fully custom provider (key is not a preset name):~
->lua
- vim.g.preview = {
- rst = {
- cmd = { 'rst2html' },
- args = function(ctx)
- return { ctx.file }
- end,
- output = function(ctx)
- return ctx.file:gsub('%.rst$', '.html')
- end,
- },
- }
-<
-
-==============================================================================
-PRESETS *preview.nvim-presets*
-
-preview.nvim ships with pre-built provider configurations for common tools.
-Import them from `preview.presets`:
-
- `presets.typst` typst compile → PDF
- `presets.latex` latexmk -pdf → PDF (with clean support)
- `presets.pdflatex` pdflatex → PDF (single pass, no latexmk)
- `presets.tectonic` tectonic → PDF (Rust-based LaTeX engine)
- `presets.markdown` pandoc → HTML (standalone, embedded)
- `presets.github` pandoc → HTML (GitHub-styled, `-f gfm` input)
- `presets.asciidoctor` asciidoctor → HTML (AsciiDoc with SSE reload)
- `presets.quarto` quarto render → HTML (scientific publishing)
-
-Enable presets with `preset_name = true`:
->lua
- vim.g.preview = { typst = true, latex = true, github = true }
-<
-
-Override individual fields by passing a table instead of `true`:
->lua
- vim.g.preview = {
- typst = { env = { TYPST_FONT_PATHS = '/usr/share/fonts' } },
- }
-<
-
-==============================================================================
-COMMANDS *preview.nvim-commands*
-
-:Preview [subcommand] *:Preview*
-
- Subcommands:~
-
- `toggle` Toggle auto-compile on save (default if omitted).
- `compile` One-shot compile of the current buffer.
- `clean` Run the provider's clean command.
- `open` Open the last compiled output without recompiling.
- `status` Echo compilation status (idle, compiling, watching).
-
-==============================================================================
-API *preview.nvim-api*
-
-preview.toggle({bufnr?}) *preview.toggle()*
- Toggle auto-compile for the buffer. When enabled, the buffer is
- immediately compiled and automatically recompiled on each save
- (`BufWritePost`). Call again to stop.
-
-preview.compile({bufnr?}) *preview.compile()*
- One-shot compile the document in the given buffer (default: current).
-
-preview.stop({bufnr?}) *preview.stop()*
- Kill the active compilation process for the buffer. Programmatic
- escape hatch — not exposed as a subcommand.
-
-preview.clean({bufnr?}) *preview.clean()*
- Run the provider's clean command for the buffer.
-
-preview.open({bufnr?}) *preview.open()*
- Open the last compiled output for the buffer without recompiling.
-
-preview.status({bufnr?}) *preview.status()*
- Returns a |preview.Status| table.
-
-preview.statusline({bufnr?}) *preview.statusline()*
- Returns a short status string for statusline integration:
- `'compiling'`, `'watching'`, or `''` (idle).
-
- *preview.Status*
-Status fields:~
-
- `compiling` boolean Whether compilation is active.
- `watching` boolean Whether auto-compile is active.
- `provider` string? Name of the active provider.
- `output_file` string? Path to the output file.
-
-preview.get_config() *preview.get_config()*
- Returns the resolved |preview.Config|.
-
-==============================================================================
-EVENTS *preview.nvim-events*
-
-preview.nvim fires User autocmds with structured data:
-
-`PreviewCompileStarted` Compilation began.
- data: `{ bufnr, provider }`
-
-`PreviewCompileSuccess` Compilation succeeded (exit code 0).
- data: `{ bufnr, provider, output }`
-
-`PreviewCompileFailed` Compilation failed (non-zero exit).
- data: `{ bufnr, provider, code, stderr }`
-
-Example:~
->lua
- vim.api.nvim_create_autocmd('User', {
- pattern = 'PreviewCompileSuccess',
- callback = function(args)
- local data = args.data
- vim.notify('Compiled ' .. data.output .. ' with ' .. data.provider)
- end,
- })
-<
-
-==============================================================================
-HEALTH *preview.nvim-health*
-
-Run `:checkhealth preview` to verify:
-
-- Neovim version >= 0.11.0
-- Each configured provider's binary is executable
-- Each configured provider's opener binary (if any) is executable
-- Each configured provider's filetype mapping is valid
-
-==============================================================================
- vim:tw=78:ts=8:ft=help:norl:
diff --git a/doc/preview.txt b/doc/preview.txt
new file mode 100644
index 0000000..0e54a62
--- /dev/null
+++ b/doc/preview.txt
@@ -0,0 +1,274 @@
+*preview.txt* Async document compilation for Neovim
+
+Author: Barrett Ruth
+License: MIT
+
+==============================================================================
+INTRODUCTION *preview.nvim*
+
+preview.nvim is an extensible framework for compiling documents asynchronously
+in Neovim. It provides a unified interface for any compilation workflow —
+LaTeX, Typst, Markdown, or anything else with a CLI compiler.
+
+The plugin ships with opt-in presets for common tools (Typst, LaTeX, Pandoc,
+AsciiDoc, Quarto) and supports fully custom providers.
+See |preview-presets|.
+
+==============================================================================
+CONTENTS *preview-contents*
+
+ 1. Introduction ............................................. |preview.nvim|
+ 2. Requirements ..................................... |preview-requirements|
+ 3. Install ............................................... |preview-install|
+ 4. Configuration ........................................... |preview-config|
+ 5. Presets ............................................... |preview-presets|
+ 6. Commands ............................................. |preview-commands|
+ 7. Lua API ................................................... |preview-api|
+ 8. Events ............................................... |preview-events|
+ 9. Health ............................................... |preview-health|
+
+==============================================================================
+REQUIREMENTS *preview-requirements*
+
+- Neovim >= 0.11.0
+- A compiler binary for each configured provider (e.g. `typst`, `latexmk`)
+
+==============================================================================
+INSTALL *preview-install*
+
+Install with lazy.nvim: >lua
+ { 'barrettruth/preview.nvim' }
+<
+
+No `setup()` call is needed. The plugin loads automatically when
+|vim.g.preview| is set. See |preview-config|.
+
+==============================================================================
+CONFIGURATION *preview-config*
+
+Configure by setting |vim.g.preview| to a table where keys are preset names
+or filetypes. For each key `k` with value `v` (excluding `debug`):
+
+ - If `k` is a preset name and `v` is `true`, the preset is registered
+ as-is under its filetype.
+ - If `k` is a preset name and `v` is a table, it is deep-merged with
+ the preset and registered under the preset's filetype.
+ - If `k` is not a preset name and `v` is a table, it is registered
+ directly as a custom provider keyed by filetype `k`.
+ - If `v` is `false`, the entry is skipped (no-op).
+
+See |preview-presets| for available preset names.
+
+ *preview.ProviderConfig*
+Provider fields: ~
+
+ {cmd} (string[]) Compiler command (required).
+
+ {args} (string[]|function) Additional arguments. If a function,
+ receives a |preview.Context| and
+ returns a string[].
+
+ {cwd} (string|function) Working directory. If a function,
+ receives a |preview.Context|.
+ Default: git root or file directory.
+
+ {env} (table) Environment variables.
+
+ {output} (string|function) Output file path. If a function,
+ receives a |preview.Context|.
+
+ {error_parser} (function) Receives (output, |preview.Context|)
+ and returns vim.Diagnostic[].
+
+ {errors} (false|'diagnostic'|'quickfix')
+ How parse errors are reported.
+ `false` suppresses error handling.
+ `'quickfix'` populates the quickfix
+ list and opens it.
+ Default: `'diagnostic'`.
+
+ {clean} (string[]|function) Command to remove build artifacts.
+ If a function, receives a
+ |preview.Context|.
+
+ {open} (boolean|string[]) Open the output file after the first
+ successful compilation in toggle/watch
+ mode. `true` uses |vim.ui.open()|. A
+ string[] is run as a command with the
+ output path appended. When a string[]
+ is used the viewer process is tracked
+ and sent SIGTERM when the buffer is
+ deleted. `true` and single-instance
+ apps (e.g. Chrome) do not support
+ auto-close.
+
+ {reload} (boolean|string[]|function)
+ Reload the output after recompilation.
+ `true` uses a built-in SSE server for
+ HTML files. A string[] is run as a
+ command. If a function, receives a
+ |preview.Context| and returns a
+ string[].
+
+ {detach} (boolean) When `true`, the viewer process opened
+ via a string[] `open` command is not
+ sent SIGTERM when the buffer is
+ deleted. Has no effect when `open` is
+ `true`. Default: `false`.
+
+ *preview.Context*
+Context fields: ~
+
+ {bufnr} (integer) Buffer number.
+ {file} (string) Absolute file path.
+ {root} (string) Project root (git root or file directory).
+ {ft} (string) Filetype.
+ {output} (string?) Resolved output file path (set after `output`
+ is evaluated, available to `args` functions).
+
+Global options: ~
+
+ {debug} (boolean|string) Enable debug logging. A string value is treated
+ as a log file path. Default: `false`.
+
+Example enabling presets: >lua
+ vim.g.preview = { typst = true, latex = true, github = true }
+<
+
+Example overriding a preset field: >lua
+ vim.g.preview = {
+ typst = { open = { 'sioyek', '--new-instance' } },
+ }
+<
+
+Example overriding the output path (e.g. latexmk `$out_dir`): >lua
+ vim.g.preview = {
+ latex = {
+ output = function(ctx)
+ return 'build/' .. vim.fn.fnamemodify(ctx.file, ':t:r') .. '.pdf'
+ end,
+ },
+ }
+<
+
+Example with a fully custom provider (key is not a preset name): >lua
+ vim.g.preview = {
+ rst = {
+ cmd = { 'rst2html' },
+ args = function(ctx)
+ return { ctx.file }
+ end,
+ output = function(ctx)
+ return ctx.file:gsub('%.rst$', '.html')
+ end,
+ },
+ }
+<
+
+==============================================================================
+PRESETS *preview-presets*
+
+Built-in provider configurations. Enable with `preset_name = true` or
+override individual fields by passing a table instead: >lua
+ vim.g.preview = { typst = true, latex = true, github = true }
+<
+
+ `typst` typst compile → PDF
+ `latex` latexmk -pdf → PDF (with clean support)
+ `pdflatex` pdflatex → PDF (single pass, no latexmk)
+ `tectonic` tectonic → PDF (Rust-based LaTeX engine)
+ `markdown` pandoc → HTML (standalone, embedded)
+ `github` pandoc → HTML (GitHub-styled, `-f gfm` input)
+ `asciidoctor` asciidoctor → HTML (AsciiDoc with SSE reload)
+ `quarto` quarto render → HTML (scientific publishing)
+
+==============================================================================
+COMMANDS *preview-commands*
+
+:Preview [subcommand] *:Preview*
+
+ Subcommands: ~
+
+ `toggle` Toggle auto-compile on save (default if omitted).
+ `compile` One-shot compile of the current buffer.
+ `clean` Run the provider's clean command.
+ `open` Open the last compiled output without recompiling.
+ `status` Echo compilation status (idle, compiling, watching).
+
+==============================================================================
+LUA API *preview-api*
+
+preview.toggle({bufnr?}) *preview.toggle()*
+ Toggle auto-compile for the buffer. When enabled, the buffer is
+ immediately compiled and automatically recompiled on each save
+ (`BufWritePost`). Call again to stop.
+
+preview.compile({bufnr?}) *preview.compile()*
+ One-shot compile the document in the given buffer (default: current).
+
+preview.stop({bufnr?}) *preview.stop()*
+ Kill the active compilation process for the buffer. Programmatic
+ escape hatch — not exposed as a subcommand.
+
+preview.clean({bufnr?}) *preview.clean()*
+ Run the provider's clean command for the buffer.
+
+preview.open({bufnr?}) *preview.open()*
+ Open the last compiled output for the buffer without recompiling.
+
+preview.status({bufnr?}) *preview.status()*
+ Returns a |preview.Status| table.
+
+preview.statusline({bufnr?}) *preview.statusline()*
+ Returns a short status string for statusline integration:
+ `'compiling'`, `'watching'`, or `''` (idle).
+
+preview.get_config() *preview.get_config()*
+ Returns the resolved |preview.Config|.
+
+ *preview.Status*
+Status fields: ~
+
+ {compiling} (boolean) Whether compilation is active.
+ {watching} (boolean) Whether auto-compile is active.
+ {provider} (string?) Name of the active provider.
+ {output_file} (string?) Path to the output file.
+
+==============================================================================
+EVENTS *preview-events*
+
+preview.nvim fires User autocmds with structured data:
+
+`PreviewCompileStarted` Compilation began.
+ data: `{ bufnr, provider }`
+
+`PreviewCompileSuccess` Compilation succeeded (exit code 0).
+ data: `{ bufnr, provider, output }`
+
+`PreviewCompileFailed` Compilation failed (non-zero exit).
+ data: `{ bufnr, provider, code, stderr }`
+
+Example: >lua
+ vim.api.nvim_create_autocmd('User', {
+ pattern = 'PreviewCompileSuccess',
+ callback = function(args)
+ local data = args.data
+ vim.notify('Compiled ' .. data.output .. ' with ' .. data.provider)
+ end,
+ })
+<
+
+==============================================================================
+HEALTH *preview-health*
+
+Run |:checkhealth| preview to verify your setup: >vim
+ :checkhealth preview
+<
+
+Checks: ~
+- Neovim version >= 0.11.0
+- Each configured provider's binary is executable
+- Each configured provider's opener binary (if any) is executable
+
+==============================================================================
+ vim:tw=78:ts=8:ft=help:norl:
From 23aa8acc55402d0a53fc5d14e0d2563a721f0eb0 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Thu, 5 Mar 2026 09:32:33 -0500
Subject: [PATCH 09/12] feat: add `plantuml` preset (#45)
Problem: PlantUML (`.puml`) diagrams have no built-in preview support,
and Neovim lacks filetype detection for PlantUML files.
Solution: Add a `plantuml` preset that compiles to SVG via `plantuml
-tsvg`, with an error parser for `Error line N` diagnostics. Register
`.puml` and `.pu` extensions via `vim.filetype.add` when the preset is
configured. Add `plantuml` to the nix dev shell.
---
flake.nix | 1 +
lua/preview/init.lua | 6 ++++++
lua/preview/presets.lua | 31 +++++++++++++++++++++++++++++++
3 files changed, 38 insertions(+)
diff --git a/flake.nix b/flake.nix
index 91a0ab2..4ae4479 100644
--- a/flake.nix
+++ b/flake.nix
@@ -32,6 +32,7 @@
pkgs.stylua
pkgs.selene
pkgs.lua-language-server
+ pkgs.plantuml
];
};
});
diff --git a/lua/preview/init.lua b/lua/preview/init.lua
index 322b893..7cb982b 100644
--- a/lua/preview/init.lua
+++ b/lua/preview/init.lua
@@ -105,6 +105,12 @@ function M.setup(opts)
vim.validate(prefix .. '.detach', provider.detach, 'boolean', true)
end
+ if providers['plantuml'] then
+ vim.filetype.add({
+ extension = { puml = 'plantuml', pu = 'plantuml' },
+ })
+ end
+
config = vim.tbl_deep_extend('force', default_config, {
debug = debug,
providers = providers,
diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua
index 3591a21..e7c51e3 100644
--- a/lua/preview/presets.lua
+++ b/lua/preview/presets.lua
@@ -271,6 +271,37 @@ M.asciidoctor = {
reload = true,
}
+---@type preview.ProviderConfig
+M.plantuml = {
+ ft = 'plantuml',
+ cmd = { 'plantuml' },
+ args = function(ctx)
+ return { '-tsvg', ctx.file }
+ end,
+ output = function(ctx)
+ return (ctx.file:gsub('%.puml$', '.svg'))
+ end,
+ error_parser = function(output)
+ local diagnostics = {}
+ for line in output:gmatch('[^\r\n]+') do
+ local lnum = line:match('^Error line (%d+) in file:')
+ if lnum then
+ table.insert(diagnostics, {
+ lnum = tonumber(lnum) - 1,
+ col = 0,
+ message = line,
+ severity = vim.diagnostic.severity.ERROR,
+ })
+ end
+ end
+ return diagnostics
+ end,
+ clean = function(ctx)
+ return { 'rm', '-f', (ctx.file:gsub('%.puml$', '.svg')) }
+ end,
+ open = true,
+}
+
---@type preview.ProviderConfig
M.quarto = {
ft = 'quarto',
From 31dcf9c91fb607ff3307b51992cef1c8b8a46ff3 Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Thu, 5 Mar 2026 10:44:33 -0500
Subject: [PATCH 10/12] feat: add `mermaid` preset (#46)
Problem: no built-in support for compiling mermaid diagrams via `mmdc`.
Solution: add a `mermaid` preset that compiles `.mmd` files to SVG and
parses `Parse error on line N` diagnostics from stderr. Add
`mermaid-cli` to the nix dev shell.
---
flake.nix | 1 +
lua/preview/presets.lua | 31 +++++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/flake.nix b/flake.nix
index 4ae4479..d5bdae4 100644
--- a/flake.nix
+++ b/flake.nix
@@ -33,6 +33,7 @@
pkgs.selene
pkgs.lua-language-server
pkgs.plantuml
+ pkgs.mermaid-cli
];
};
});
diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua
index e7c51e3..1b5333e 100644
--- a/lua/preview/presets.lua
+++ b/lua/preview/presets.lua
@@ -302,6 +302,37 @@ M.plantuml = {
open = true,
}
+---@type preview.ProviderConfig
+M.mermaid = {
+ ft = 'mermaid',
+ cmd = { 'mmdc' },
+ args = function(ctx)
+ return { '-i', ctx.file, '-o', ctx.output }
+ end,
+ output = function(ctx)
+ return (ctx.file:gsub('%.mmd$', '.svg'))
+ end,
+ error_parser = function(output)
+ local diagnostics = {}
+ for line in output:gmatch('[^\r\n]+') do
+ local lnum = line:match('^%s*Parse error on line (%d+)')
+ if lnum then
+ table.insert(diagnostics, {
+ lnum = tonumber(lnum) - 1,
+ col = 0,
+ message = line,
+ severity = vim.diagnostic.severity.ERROR,
+ })
+ end
+ end
+ return diagnostics
+ end,
+ clean = function(ctx)
+ return { 'rm', '-f', (ctx.file:gsub('%.mmd$', '.svg')) }
+ end,
+ open = true,
+}
+
---@type preview.ProviderConfig
M.quarto = {
ft = 'quarto',
From 6f090fdcf33155cb116b898109c6dcaa106e6e4a Mon Sep 17 00:00:00 2001
From: Barrett Ruth
Date: Thu, 5 Mar 2026 10:55:03 -0500
Subject: [PATCH 11/12] build: split nix dev shell into `default` and `presets`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Problem: the single dev shell mixed dev tooling (linters, test runner)
with preset compiler tools, causing heavy rebuilds (e.g. Chromium for
`mermaid-cli`) for contributors who only need the dev tools.
Solution: extract dev tooling into a shared `devTools` list and expose
two shells — `default` for development and `presets` for running all
built-in preset compilers (`typst`, `texliveMedium`, `tectonic`,
`pandoc`, `asciidoctor`, `quarto`, `plantuml`, `mermaid-cli`).
---
flake.nix | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/flake.nix b/flake.nix
index 4ae4479..636f4d0 100644
--- a/flake.nix
+++ b/flake.nix
@@ -19,9 +19,9 @@
{
formatter = forEachSystem (pkgs: pkgs.nixfmt-tree);
- devShells = forEachSystem (pkgs: {
- default = pkgs.mkShell {
- packages = [
+ devShells = forEachSystem (pkgs:
+ let
+ devTools = [
(pkgs.luajit.withPackages (
ps: with ps; [
busted
@@ -32,9 +32,24 @@
pkgs.stylua
pkgs.selene
pkgs.lua-language-server
- pkgs.plantuml
];
- };
- });
+ in
+ {
+ default = pkgs.mkShell {
+ packages = devTools;
+ };
+ presets = pkgs.mkShell {
+ packages = devTools ++ [
+ pkgs.typst
+ pkgs.texliveMedium
+ pkgs.tectonic
+ pkgs.pandoc
+ pkgs.asciidoctor
+ pkgs.quarto
+ pkgs.plantuml
+ pkgs.mermaid-cli
+ ];
+ };
+ });
};
}
From 9fe68dd159fd4f2405f57d5026ea40f0c7b251ae Mon Sep 17 00:00:00 2001
From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
Date: Thu, 5 Mar 2026 11:03:43 -0500
Subject: [PATCH 12/12] docs: document `plantuml` and `mermaid` presets (#47)
Problem: the README and vimdoc presets list omitted `plantuml` and
`mermaid` after both were added.
Solution: add both presets to the vimdoc table and the README features
blurb.
---
README.md | 2 +-
doc/preview.txt | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 3ffbc38..80a2650 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Typst, Markdown, etc.)—diagnostics included.
- Async compilation via `vim.system()`
- Built-in presets for Typst, LaTeX (latexmk, pdflatex, tectonic), Markdown,
- GitHub-flavored Markdown, AsciiDoc, and Quarto
+ GitHub-flavored Markdown, AsciiDoc, PlantUML, Mermaid, and Quarto
- Compiler errors via `vim.diagnostic` or quickfix
- Previewer auto-close on buffer deletion
diff --git a/doc/preview.txt b/doc/preview.txt
index 0e54a62..383a8f5 100644
--- a/doc/preview.txt
+++ b/doc/preview.txt
@@ -11,7 +11,7 @@ in Neovim. It provides a unified interface for any compilation workflow —
LaTeX, Typst, Markdown, or anything else with a CLI compiler.
The plugin ships with opt-in presets for common tools (Typst, LaTeX, Pandoc,
-AsciiDoc, Quarto) and supports fully custom providers.
+AsciiDoc, PlantUML, Mermaid, Quarto) and supports fully custom providers.
See |preview-presets|.
==============================================================================
@@ -180,6 +180,8 @@ override individual fields by passing a table instead: >lua
`markdown` pandoc → HTML (standalone, embedded)
`github` pandoc → HTML (GitHub-styled, `-f gfm` input)
`asciidoctor` asciidoctor → HTML (AsciiDoc with SSE reload)
+ `plantuml` plantuml → SVG (UML diagrams, `.puml`)
+ `mermaid` mmdc → SVG (Mermaid diagrams, `.mmd`)
`quarto` quarto render → HTML (scientific publishing)
==============================================================================