preview.nvim/doc/preview.txt
Barrett Ruth 535d4cfd5e
docs: add FAQ entry for redirecting markdown output to /tmp (#56)
Problem: the `markdown` and `github` presets write `.html` output to the
working directory, which clutters the project.

Solution: add a FAQ entry to both `README.md` and `doc/preview.txt`
showing how to override the `output` field to redirect to `/tmp`.
2026-03-11 15:43:13 -04:00

448 lines
17 KiB
Text

*preview.txt* Async document compilation for Neovim
Author: Barrett Ruth <br.barrettruth@gmail.com>
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, PlantUML, Mermaid, 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|
- Math rendering ....................................... |preview-math|
6. Commands ............................................. |preview-commands|
7. Lua API ................................................... |preview-api|
8. Events ............................................... |preview-events|
9. Health ............................................... |preview-health|
10. FAQ ..................................................... |preview-faq|
11. SyncTeX ............................................. |preview-synctex|
==============================================================================
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[].
{extra_args} (string[]|function) Appended to {args} after evaluation.
Useful for adding flags to a preset
without replacing its defaults.
{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, KaTeX math)
`github` pandoc → HTML (GitHub-styled, `-f gfm`, KaTeX math)
`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)
Math rendering (pandoc presets): ~
*preview-math*
The `markdown` and `github` presets use `--katex` by default, which inserts a
`<script>` tag that loads KaTeX from a CDN at view time. The browser fetches
the assets once and caches them, so math renders instantly on subsequent loads.
Requires internet on first view.
For offline use, swap in `--mathml` via `extra_args`. MathML is rendered
natively by the browser with no external dependencies: >lua
vim.g.preview = {
github = { extra_args = { '--mathml' } },
}
<
Note: pandoc's math flags (`--katex`, `--mathml`, `--mathjax`) are mutually
exclusive — last flag wins. Adding `--mathml` via `extra_args` (which is
appended after `args`) overrides `--katex`.
Self-contained output with `--embed-resources`: >lua
vim.g.preview = {
github = { extra_args = { '--embed-resources' } },
}
<
This inlines all external resources into the HTML. With `--katex` this adds
~15s of compile time per save (pandoc fetches KaTeX from the CDN during
compilation). Pair with `--mathml` to avoid the penalty: >lua
vim.g.preview = {
github = { extra_args = { '--embed-resources', '--mathml' } },
}
<
==============================================================================
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
==============================================================================
FAQ *preview-faq*
Q: Markdown/GFM compilation drops `.html` files in my working directory.
How do I send output to `/tmp` instead?
A: Override the `output` field. The `args` function references `ctx.output`,
so the compiled file lands wherever `output` points: >lua
vim.g.preview = {
github = {
output = function(ctx)
return '/tmp/' .. vim.fn.fnamemodify(ctx.file, ':t:r') .. '.html'
end,
},
}
<
==============================================================================
SYNCTEX *preview-synctex*
SyncTeX enables bidirectional navigation between LaTeX source and the
compiled PDF. The `latex` preset compiles with `-synctex=1` by default.
Forward search (editor -> viewer) requires caching the output path.
Inverse search (viewer -> editor) requires a fixed Neovim server socket.
The following configs leverage the below basic setup: ~
>lua
vim.fn.serverstart('/tmp/nvim-preview.sock')
local synctex_pdf = {}
vim.api.nvim_create_autocmd('User', {
pattern = 'PreviewCompileSuccess',
callback = function(args)
synctex_pdf[args.data.bufnr] = args.data.output
end,
})
<
The recipes below bind `<leader>s` for forward search. To scroll the PDF
automatically on cursor movement, call the forward search function from a
|CursorMoved| or |CursorHold| autocmd instead.
Viewer-specific recipes: ~
*preview-synctex-zathura*
Zathura ~
Inverse search: Ctrl+click.
>lua
vim.keymap.set('n', '<leader>s', function()
local pdf = synctex_pdf[vim.api.nvim_get_current_buf()]
if pdf then
vim.fn.jobstart({
'zathura', '--synctex-forward',
vim.fn.line('.') .. ':0:' .. vim.fn.expand('%:p'), pdf,
})
end
end)
vim.g.preview = {
latex = {
open = {
'zathura',
'--synctex-editor-command',
'nvim --server /tmp/nvim-preview.sock'
.. [[ --remote-expr "execute('b +%{line} %{input}')"]],
},
},
}
<
*preview-synctex-sioyek*
Sioyek ~
Inverse search: right-click with synctex mode active.
Add to `~/.config/sioyek/prefs_user.config`: >
inverse_search_command nvim --server /tmp/nvim-preview.sock --remote-expr "execute('b +%2 %1')"
<
>lua
vim.keymap.set('n', '<leader>s', function()
local pdf = synctex_pdf[vim.api.nvim_get_current_buf()]
if pdf then
vim.fn.jobstart({
'sioyek',
'--instance-name', 'preview',
'--forward-search-file', vim.fn.expand('%:p'),
'--forward-search-line', tostring(vim.fn.line('.')),
pdf,
})
end
end)
vim.g.preview = {
latex = {
open = { 'sioyek', '--instance-name', 'preview' },
},
}
<
*preview-synctex-okular*
Okular ~
Inverse search (Shift+click): one-time GUI setup via
Settings -> Configure Okular -> Editor -> Custom Text Editor: >
nvim --server /tmp/nvim-preview.sock --remote-expr "execute('b +%l %f')"
<
>lua
vim.keymap.set('n', '<leader>s', function()
local pdf = synctex_pdf[vim.api.nvim_get_current_buf()]
if pdf then
vim.fn.jobstart({
'okular', '--unique',
('%s#src:%d:%s'):format(pdf, vim.fn.line('.'), vim.fn.expand('%:p')),
})
end
end)
vim.g.preview = {
latex = { open = { 'okular', '--unique' } },
}
<
==============================================================================
vim:tw=78:ts=8:ft=help:norl: