Render LaTeX math written inside code comments as Unicode/ASCII art, inline.
It is inspired by nabla.nvim and reuses its math engine, but fixes the one thing that makes nabla annoying while writing code:
nabla parses the whole buffer as LaTeX, so every
$that legitimately appears in your code (shell variables$HOME, JS template literals${x}, regex, PHP/Perl, …) gets rendered as a math formula.
cxMathPreview only renders $ ... $ that lives inside a comment. The
real code is never touched.
// energy-mass equivalence: $E = mc^2$ <- rendered inline as E = mc²
int price = 5; // $price stays $price, it's code- Find comment regions of the visible lines (treesitter
@commentnodes when a parser is available, falling back to Vim's built-in syntax highlighting — so it works out of the box without any treesitter parsers). - Inside those comment regions only, scan for inline math
$ ... $(and display math$$ ... $$).\$is treated as a literal dollar, not math. - Convert each math snippet with the vendored nabla engine
(
latex.luaparser →ascii.luarenderer) into Unicode/ASCII art. - Show the art inline — the raw
$...$is concealed and replaced by the rendered formula (like nabla).
- Neovim 0.9+ (uses
vim.treesitter, extmarks, virtual text). - For best comment detection: a treesitter parser for your filetype
(
:TSInstall <lang>). Not required — the syntax fallback works for almost every filetype out of the box. conceallevel >= 2is set automatically while enabled (and restored on disable). Your terminal/font must have glyphs like∑ ∫ √ ² ³ ≈ ≤ α β. A Nerd Font is not required.
Since the repo ends in .nvim, lazy.nvim derives main = "cxMathPreview"
automatically, so you can use the opts shorthand:
{
"cxwx/cxMathPreview.nvim",
opts = {
-- see options below
},
-- Optional: lazy-load on the commands / a key
-- cmd = { "CxMathEnable", "CxMathToggle", "CxMathPopup" },
-- keys = { { "<leader>m", "<cmd>CxMathPopup<cr>" } },
}Or with an explicit config:
{
"your-name/cxMathPreview.nvim",
config = function()
require("cxMathPreview").setup({
-- see options below
})
end,
}use {
"your-name/cxMathPreview.nvim",
config = function() require("cxMathPreview").setup() end
}Commands (available immediately):
| Command | Description |
|---|---|
:CxMathToggle |
Toggle inline rendering for the current buffer |
:CxMathPopup |
Show the $...$ formula under the cursor in a float |
The Lua API also exposes enable() / disable() / is_enabled() if you want
finer control.
Recommended keymap:
vim.keymap.set("n", "<leader>m", function() require("cxMathPreview").popup() end,
{ desc = "Math popup" })
vim.keymap.set("n", "<leader>M", function() require("cxMathPreview").toggle() end,
{ desc = "Toggle inline math" })There is essentially one option — the highlight group used for rendered math.
Everything else (inline conceal, multi-line alignment, concealcursor) is
hardcoded. You can skip setup() entirely.
require("cxMathPreview").setup({ hl = "SpecialChar" }) -- defaultA Python file with:
# likelihood: $\mathcal{L}(\theta) = \prod_{i=1}^{n} p(x_i \mid \theta)$
# fraction: $\frac{1}{1 + e^{-x}}$renders (inline) roughly as:
# likelihood: n
# ─┬─┬─
# ‖ p(xᵢ ∣ θ)
# i = 1
# fraction: 1
# ───────
# -x
# 1 + e
local cx = require("cxMathPreview")
cx.setup(opts) -- configure + optional auto-enable by filetype
cx.enable(buf?) -- enable for buffer (default current)
cx.disable(buf?)
cx.toggle(buf?)
cx.is_enabled(buf?)
cx.popup() -- floating preview of the formula under cursor
cx.render(buf?) -- force a re-render (rarely needed; auto-refreshes)The LaTeX parser (lua/cxMathPreview/latex.lua) and ASCII renderer
(lua/cxMathPreview/ascii.lua) are vendored unchanged from
nabla.nvim by jbyuki (MIT License,
Copyright (c) 2020 jbyuki). The comment-aware layer on top is original.
MIT.