中文版文档:zh-cn
Faster and More Precise LaTeX and typst conceal for Neovim.
typst-showcase.mov
stream-showcase.mov
- High performance conceal for LaTeX and typst files.
- Fine grained conceal patterns:
- Original neovim conceal patterns: expand all concealed nodes on the line where the cursor is located.
- Fine grained conceal patterns: only expand the concealed node under the cursor.
- Image overlay conceal: Using kitty graphic protocol to show the compiled equations instead of source code.
- Support multiple conceal patterns, including greek letters, script letters, math symbols, font styles, delimiters, and physical units.
- Multiple highlight groups for different conceal patterns, allowing you to customize the appearance of each pattern (all highlight groups can be found in highlights).
:Rocks install math-conceal.nvim~/.config/nvim/rocks.toml:
[plugins]
"math-conceal.nvim" = "scm"Then
:Rocks syncor:
$ luarocks --lua-version 5.1 --local --tree ~/.local/share/nvim/rocks install math-conceal.nvim
# ~/.local/share/nvim/rocks is the default rocks tree path
# you can change it according to your vim.g.rocks_nvim.rocks_pathGraphical equation conceal also needs the optional Rust service binary:
:Rocks install math-conceal-serviceor:
$ luarocks --lua-version 5.1 --local --tree ~/.local/share/nvim/rocks install math-conceal-serviceLuaRocks uses a prebuilt service rock when one is available for your platform; otherwise it builds the service from source and requires Rust/Cargo.
return {
"pxwg/math-conceal.nvim",
event = "VeryLazy",
main = "math-conceal",
build = "cargo build --release --manifest-path service/Cargo.toml", -- required for graphical equation conceal
--- @type LaTeXConcealOptions
opts = {
conceal = {
"greek",
"script",
"math",
"font",
"delim",
"phy",
},
ft = { "plaintex", "tex", "context", "bibtex", "markdown", "typst" },
opt = {
conceallevel = 2,
concealcursor = "n",
},
image = {
enabled = true, -- set true to enable graphical equation conceal
},
},
}The top-level opt table controls the Neovim window-local conceal options that
math-conceal injects only into windows showing attached buffers. The default
concealcursor = "n" keeps conceal active in Normal mode while revealing source
on the cursor line during Insert mode; set it to "nci" to keep the previous
always-concealed cursor-line behavior.
attach() is the common entry point for ASCII/Unicode and graphical conceal.
Ordinary filetype buffers are attached automatically. Integrations for virtual
or preview buffers can provide the logical source independently of the
buffer's concrete filetype and name:
local conceal = require("math-conceal")
local attachment = conceal.attach(bufnr, {
source = {
kind = "markdown", -- "latex", "markdown", or "typst"
filetype = "markdown",
path = "/absolute/path/to/note.md",
},
surfaces = {
unicode = true,
image = true,
},
mode = "presentation",
})
attachment:detach()path supplies the real source provenance for renderer roots, imports, and
path filters when the attached buffer is anonymous. image = true still
requires top-level image.enabled = true; graphical attachment is available
for Typst and Markdown, while LaTeX uses ASCII/Unicode conceal only.
Calls return owner-qualified handles. Multiple integrations may attach the
same logical source to one buffer, and detaching one handle leaves the other
owners active. Re-attaching with the same explicit owner replaces that
owner's request and makes its old handle stale. Use
resolve_source(bufnr, source), get_attachment(bufnr), refresh(), or
detach(bufnr) for custom integrations and lifecycle inspection.
The source descriptor determines the Tree-sitter root parser explicitly. math-conceal obtains that parser but does not start or stop Tree-sitter highlighting, so preview hosts remain responsible for their own highlighter lifecycle.
The stock Snacks.picker.preview.file previewer is adapted automatically when
Snacks is available. Scratch previews use presentation mode, while previews
that reuse an already-loaded buffer preserve that buffer's existing mode and
attachment owner. Typst, Markdown, and LaTeX previews receive Unicode conceal;
Typst and Markdown also request image conceal when it is globally enabled.
require("math-conceal").setup({
integrations = {
snacks = {
enabled = true, -- default
unicode = true,
image = true,
mode = "presentation",
},
},
})Disable the default adapter with integrations.snacks = false. Custom Snacks
previewers can reuse the same lifecycle:
local snacks_conceal = require("math-conceal.integrations.snacks")
opts.preview = snacks_conceal.wrap(my_synchronous_previewer, {
source = function(ctx, bufnr, detected)
return detected -- customize kind, filetype, or path here
end,
})For asynchronous previewers, call snacks_conceal.sync(ctx, opts) after the
preview content has been committed and snacks_conceal.detach(ctx) during
custom cleanup.
math-conceal.nvim can also render equations as terminal graphics using the renderer
adapted from pxwg/typst-concealer,
which is a fork of PartyWumpus/typst-concealer.
This path uses kitty graphics protocol and works in terminals that support it,
such as kitty and Ghostty.
Graphical equation conceal supports Typst and Markdown math through
MiTeX.
Markdown math supports $...$ and $$...$$ through Tree-sitter by default.
Set image.renderers.markdown.backslash_math = true to also recognize
\(...\) and \[...\]. This optional handwritten scanner scans the full
buffer and is disabled by default to avoid its additional scanning cost.
The graphical path requires Neovim 0.11 or newer; ASCII/Unicode conceal does not.
Enable it from the same setup table:
require("math-conceal").setup({
image = {
enabled = true,
renderers = {
typst = {
filetypes = { "typst" },
},
markdown = {
filetypes = { "markdown" },
mitex_package = "@preview/mitex:0.2.7",
},
},
},
})Display math is centered by default. Set image.block_align = "source" to
align Typst and Markdown display math with its source column instead.
Inline math and Typst code placement are unchanged.
For rocks.nvim installs, install the optional service rock:
:Rocks install math-conceal-serviceFor source/lazy.nvim installs, build the bundled Rust service after installing or updating:
cargo build --release --manifest-path service/Cargo.tomlCheck Neovim APIs, terminal support, adapters, and the render service with:
:checkhealth math-concealRenderer-specific options live under image.renderers.<name>, including
filetypes, service_binary, live_debounce, root, inputs,
preamble_file, header, render_paths, Typst's code_render.allow and
code_render.exclude, and Markdown's mitex_package, mitex_preamble, and
mitex_preamble_file.
Markdown MiTeX rendering can prepend reusable LaTeX macro definitions to every inline and block formula. File definitions are loaded before inline definitions:
require("math-conceal").setup({
image = {
enabled = true,
renderers = {
markdown = {
mitex_preamble = [[
\newcommand{\RR}{\mathbb{R}}
]],
mitex_preamble_file = function(ctx)
return vim.fs.dirname(ctx.path) .. "/mitex-preamble.tex"
end,
},
},
},
})These options are MiTeX macro preludes, not full LaTeX document preambles:
MiTeX-supported definitions such as \newcommand and \newenvironment work,
but they do not load LaTeX packages with \usepackage. For example, a
MiTeX-compatible \slashed approximation is:
\newcommand{\slashed}[1]{\not{#1}}After changing an external preamble file, call
require("math-conceal.image").rerender_buf() to refresh the current Markdown
buffer.
Typst code rendering is intentionally allowlisted. math-conceal renders a
built-in set of predictable Typst primitives by default. Add project-wide custom
function names with code_render.allow, or remove names from the effective
allowlist with code_render.exclude. Exclusions take precedence over both
built-in and explicitly allowed names, and match the tracked code expression's
head rather than recursively inspecting nested calls:
require("math-conceal").setup({
image = {
enabled = true,
renderers = {
typst = {
code_render = {
allow = { "theorem", "lemma", "remark" },
exclude = { "image" },
},
},
},
},
})- Better support for typst files, and customizable conceal patterns.
- LaTeX customizable conceal patterns.
- Typst customizable conceal patterns.
- Commutative diagram conceal for Typst files.
- Table conceal for LaTeX and Typst files (inspired from render-markdown.nvim).
- Automatically maintain the conceal query file and
math_symbols.jsonfile.- Typst
- LaTeX
- ts_query_lsp I use this LSP as a pre-commit hook to format the query file.
- latex_concealer.nvim for some ideas about conceal patterns.
- Freed-Wu: Instrumental in publishing this plugin to LuaRocks and refactoring the code structure to fit the best practices for Neovim plugins.
- Dirichy: for helpful discussions about LaTeX conceal patterns and optimizations.
- PartyWumpus: for the original typst-concealer plugin, which inspired Typst graphical conceal support.
- latex.nvim for the idea of using customized conceal patterns.
- latex_concealer.nvim for the idea of fine grained conceal patterns.
- pxwg/typst-concealer as the fork whose renderer source was adapted into this plugin.
