Neovim 用の Markdown レンダリングエンジンです。生の Markdown テキストをハイライト付きのインタラクティブなコンテンツに変換して、エディタ内で表示します。フローティングウィンドウ、タブ表示、コマンドラインからの less ライクなページャーモードに対応しています。
- リッチなインライン書式 — 太字、取り消し線、インラインコード、リンク、Obsidian
==highlight==をその場でレンダリング - テーブル — 罫線文字による描画、列アラインメント、比例サイズ調整、セル内インライン書式
- コールアウト & 折りたたみ — GitHub / Obsidian のアラートタイプに対応。色付きボーダー・アイコン・クリックで折りたたみ切り替え
- コードブロック — treesitter シンタックスハイライト付きフェンスコードブロック。省略時はクリックで展開
- 画像 — ローカルおよび Web 画像(PNG, JPEG, WebP, GIF, アニメーション GIF)をターミナルグラフィクスプロトコルでインライン表示
- 動画 — ローカルおよび Web 動画(MP4, WebM, MOV, AVI, MKV, M4V)をアニメーションフレームとしてインライン再生
- Mermaid ダイアグラム — 画像としてインライン表示
- CJK 対応ワードラップ — JIS X 4051 禁則処理 + BudouX(budoux.lua 経由)によるオプションのフレーズ分割
- クリック可能リンク — マウスクリックで URL を開く。対応ターミナルでは OSC 8 ハイパーリンク
<details>対応 — クリックで折りたたみ可能なセクション。open属性にも対応- ライブラリ API — レンダリングエンジンを自作プラグインからプログラム的に利用可能
リポジトリには全機能を一望できるショーケース Markdown が同梱されています。クローン後、ページャーで開いてみてください:
git clone https://github.com/delphinus/md-render.nvim
cd md-render.nvim
nvim +"MdRender pager" assets/showcase.mdプラグインをインストール済みの場合は、:MdRender demo で対応する全記法を確認できます。
- Neovim >= 0.12(端末への書き出しに
vim.api.nvim_ui_sendを使用) - 画像・動画のインライン表示には Kitty graphics protocol 対応ターミナルが必要。 動作確認は WezTerm / Kitty / Ghostty(macOS/Linux)で実施。
オプション依存
| 依存 | 用途 | フォールバック |
|---|---|---|
| curl | Web 画像・動画のダウンロード | set_download_fn() でカスタム関数を指定可 |
FFmpeg (ffmpeg / ffprobe) |
JPEG/WebP → PNG 変換、アニメーション GIF / 動画のフレーム展開 | ImageMagick にフォールバック(画像のみ。動画には ffmpeg が必要) |
ImageMagick (magick) |
JPEG/WebP → PNG、アニメーション GIF フレーム展開 | macOS では sips が静止画変換を処理。アニメーション GIF には ffmpeg か magick が必要 |
Mermaid CLI (mmdc) |
Mermaid ダイアグラムを画像として描画 | npx -y @mermaid-js/mermaid-cli にフォールバック |
| budoux.lua | CJK フレーズ単位の改行(BudouX) | 1文字ずつ分割(禁則処理は維持) |
| Treesitter パーサー | コードブロックのシンタックスハイライト | ハイライトなしで表示 |
| nvim-web-devicons または mini.icons | コードブロックヘッダのファイルタイプアイコン | 内蔵アイコンテーブル |
画像・動画のフォーマット変換とアニメーションのサポートでは、以下の優先順位でツールを検索します:
| ユースケース | 1st | 2nd | 3rd |
|---|---|---|---|
| 静止画変換(JPEG/WebP → PNG) | sips(macOS) |
ffmpeg |
magick |
| アニメーション GIF フレーム展開 | ffmpeg |
magick |
— |
| 動画フレーム展開 | ffmpeg |
— | — |
{
"delphinus/md-render.nvim",
version = "*",
dependencies = {
{ "nvim-tree/nvim-web-devicons", version = "*" }, -- optional: file type icons in code blocks
{ "delphinus/budoux.lua", version = "*" }, -- optional: CJK phrase-level line breaking
},
keys = {
{ "<leader>mp", "<Plug>(md-render-preview)", desc = "Markdown preview (toggle)" },
{ "<leader>mt", "<Plug>(md-render-preview-tab)", desc = "Markdown preview in tab (toggle)" },
{ "<leader>md", "<Plug>(md-render-demo)", desc = "Markdown render demo" },
},
}vim.pack.add({
"https://github.com/delphinus/md-render.nvim",
-- optional:
"https://github.com/nvim-tree/nvim-web-devicons",
"https://github.com/delphinus/budoux.lua",
})local add = MiniDeps.add
add({
source = "delphinus/md-render.nvim",
depends = {
"nvim-tree/nvim-web-devicons", -- optional
"delphinus/budoux.lua", -- optional
},
})他の Markdown プレビューアではダメ?
- markdown-preview.nvim — ブラウザ品質のレンダリングが必要な場合は最適ですが、ブラウザを必要とします。md-render はターミナル内で完結します。
- render-markdown.nvim — バッファ内レンダリングが美しいですが、編集中のバッファ自体を変更します。md-render は編集バッファに手を加えず、別のフローティング/タブウィンドウまたはページャーへ描画します。
- mcat — 思想として最も近い(ピュアターミナルの Markdown レンダラー)ですが、自動折りたたみテーブルやクリックで折りたたみ切り替え、CJK ワードラップなどの複雑なレイアウト機能は未対応です。
md-render.nvim は、ターミナル内で完結する専用プレビューアとして、リッチなレイアウトと第一級の CJK サポートを目指しています。
このプラグインは <Plug> マッピングを提供しますが、デフォルトのキーバインドは設定しません。自分でマッピングしてください:
vim.keymap.set("n", "<leader>mp", "<Plug>(md-render-preview)", { desc = "Markdown preview (toggle)" })
vim.keymap.set("n", "<leader>mt", "<Plug>(md-render-preview-tab)", { desc = "Markdown preview in tab (toggle)" })
vim.keymap.set("n", "<leader>md", "<Plug>(md-render-demo)", { desc = "Markdown render demo" })<Plug> マッピング |
説明 |
|---|---|
<Plug>(md-render-preview) |
現在の Markdown バッファのフローティングプレビューをトグル |
<Plug>(md-render-preview-tab) |
現在の Markdown バッファのタブプレビューをトグル |
<Plug>(md-render-toggle) |
現在のウィンドウをソース ↔ レンダーモードでその場切替 |
<Plug>(md-render-auto) |
[実験的] 現在のバッファで auto モード(Insert 以外で render)をトグル |
<Plug>(md-render-split) |
ウィンドウを分割してソースとレンダリング表示を並べる |
<Plug>(md-render-demo) |
対応する全 Markdown 記法のデモウィンドウを表示 |
このプラグインが公開するユーザコマンドは :MdRender ひとつで、サブコマンドで動作モードを切り替えます。
| コマンド | 説明 |
|---|---|
:MdRender |
フローティングプレビュー(:MdRender float のエイリアス) |
:MdRender float |
フローティングプレビューをトグル |
:MdRender tab |
タブプレビューをトグル |
:MdRender toggle |
現在のウィンドウをソース ↔ レンダーモードでその場切替 |
:MdRender split |
ウィンドウを分割してソースとレンダリング表示を並べる(:vert / :tab / :topleft / :botright を尊重) |
:MdRender auto [on|off|toggle] |
[実験的] Insert モードに連動して source/render を自動切替(バッファ単位) |
:MdRender pager |
ページャーモード — フルスクリーン、装飾なし、q で Neovim 終了 |
:MdRender demo |
対応する全 Markdown 記法のデモウィンドウを表示 |
タブ補完では第1引数としてサブコマンド一覧、auto の後では on / off / toggle が候補になります。
後方互換について。 従来のトップレベルコマンド (
:MdRenderTab、:MdRenderToggle、:MdRenderSplit、:MdRenderAuto、:MdRenderPager、:MdRenderDemo) は新しいディスパッチャへ転送されるエイリアスとして残しています。Neovim セッションごとに最初の呼び出しで非推奨警告を1度だけ表示します。将来のメジャーバージョンで削除されます。
:MdRender toggle は、現在のウィンドウをソース Markdown バッファとそのレンダリング表示の間でその場で切り替えます。新しいタブやフローティングウィンドウは開きません。スプリットレイアウトでコードと README のレンダリングを並べたい、といった用途を想定しています。
:vsplit README.md
:MdRender toggle挙動:
- レンダーバッファは読み取り専用で、トグル間で再利用されます(ソース1つにつきレンダーバッファ1つ)。
- 同じソースが複数のウィンドウで表示されている場合、切替はそのウィンドウだけに作用し、他のウィンドウの編集は次に当該ウィンドウをレンダーモードにした時点で反映されます。
- カーソル位置は source line マップを介してソース ↔ レンダー間を往復します。
- レンダーモードのウィンドウでは
number/relativenumber/listが無効化されます。元の値はウィンドウに保存され、ソースに戻したときに復元されます。 - レンダーモード中、
q/<Esc>/<CR>は閉じる動作に割り当てられません。ソースに戻すには再度:MdRender toggleを呼びます。<LeftMouse>は折りたたみ・展開・リンク open を引き続き処理します。
実験的機能です。 新しく追加された機能で、UX が変わる可能性があります。問題や違和感があればぜひお知らせください。
:MdRender auto on は、現在のバッファを Normal モード中はレンダー表示にしておき、編集を始めると自動的に source に戻すモードです。off で解除、:MdRender auto(または :MdRender auto toggle)でトグル。すべての Markdown バッファで有効にしたいときは:
autocmd FileType markdown silent! MdRender auto oni / I / a / A / o / O の再マップ、:w の source への転送、読み取り専用なレンダーバッファ上で効かない編集操作などの詳細は :help :MdRender-auto を参照してください。
:MdRender split は、現在のウィンドウを分割してソースとレンダリング表示を並べます。分割方向は標準的な Vim のモディファイアに従います:
:MdRender split— 水平分割:vert MdRender split— 垂直分割(README とコードを並べる定番):tab MdRender split— 新しいタブ内で分割:topleft MdRender split— 一番上に配置:botright MdRender split— 一番下に配置
ソースの編集はライブでもう一方のウィンドウに反映され、カーソル/スクロール位置も双方向に同期します。詳細な挙動とインライン画像の制限事項は :help :MdRender-split を参照してください。
less のように閲覧
:MdRender pager を使うと Markdown ファイルを less のように閲覧できます:
nvim +"MdRender pager" README.mdシェルエイリアスを設定すると便利です:
alias mdless='nvim +"MdRender pager"'
mdless README.mdrequire("md-render.telescope").previewer() で作成した previewer は、任意の
telescope.nvim picker
(builtin、extension、カスタム問わず)に渡せます:
local previewer = require("md-render.telescope").previewer()
require("telescope.builtin").find_files({ previewer = previewer })
require("telescope").extensions.egrepify.egrepify({ previewer = previewer })ファイルの種類に応じて自動的に表示方法を切り替えます:
| ファイル種別 | 動作 |
|---|---|
Markdown (.md, .markdown) |
md-render によるフルレンダリング(ハイライト、リンク、画像) |
| 画像・動画 (PNG, JPEG, WebP, GIF, MP4, ...) | Kitty graphics protocol でインライン表示 |
| その他 | telescope のデフォルト previewer(シンタックスハイライト付き)にフォールバック |
grep 系の picker では、マッチした行に自動スクロールします。
builtin picker 用のショートカットです。telescope.builtin の picker を md-render
previewer 付きでラップします。引数はすべてそのまま渡されます:
:Telescope md_render find_files
:Telescope md_render live_grep cwd=~/notes
:Telescope md_render grep_string search=TODOrequire("md-render.snacks").preview() で
snacks.nvim の picker 用プレビュー関数を
作成します。telescope 版と同じく Markdown、画像・動画、その他のファイルに対応します。
グローバルに全 picker へ適用:
require("snacks").setup({
picker = {
preview = require("md-render.snacks").preview(),
},
})source ごとに個別設定:
require("snacks").setup({
picker = {
sources = {
files = { preview = require("md-render.snacks").preview() },
grep = { preview = require("md-render.snacks").preview() },
},
},
})画像が表示されない(alt テキストやファイル名だけが出る)
画像のインライン表示には Kitty graphics protocol に対応したターミナルが必要です。WezTerm、Kitty、Ghostty のいずれかを使っているか確認してください。tmux などのマルチプレクサは、明示的に通過設定をしない限り画像エスケープシーケンスを破棄することがあります。
動画が静止画 1 枚しか表示されない
動画フレーム展開には ffmpeg が $PATH にインストールされている必要があります。なければ、最初のフレームを静止画として表示するフォールバックになります。パッケージマネージャでインストールしてください(例:brew install ffmpeg)。
Mermaid ダイアグラムが描画されない
Mermaid のレンダリングには @mermaid-js/mermaid-cli の mmdc バイナリが必要です。グローバルに mmdc がない場合は npx -y @mermaid-js/mermaid-cli にフォールバックしますが、初回呼び出しが大幅に遅くなります。npm install -g @mermaid-js/mermaid-cli でグローバルインストールするのがおすすめです。
日本語の折り返しが不自然
デフォルトでは JIS X 4051 の禁則処理を文字単位で適用します。自然な単語境界に従うフレーズ単位の分割が必要なら budoux.lua をインストールしてください。プラグインが自動検出して使用します。
コードブロックにシンタックスハイライトが付かない
シンタックスハイライトには対応する treesitter パーサーが必要です。例えば Lua のハイライトには :TSInstall lua(nvim-treesitter)または Neovim 0.11+ の組み込みパーサー管理を使ってインストールしてください。
プログラム API
レンダリングエンジンをプログラムから利用してハイライト付きコンテンツを構築できます:
local md = require("md-render")
-- 1 行の Markdown をレンダリング
local text, highlights, links = md.Markdown.render("**bold** and [link](https://example.com)")
-- ドキュメント全体のコンテンツを構築
local ContentBuilder = md.ContentBuilder
local b = ContentBuilder.new()
b:render_document(lines, {
max_width = 80,
indent = " ",
repo_base_url = "https://github.com/user/repo",
autolinks = {
{ key_prefix = "JIRA-", url_template = "https://jira.example.com/browse/JIRA-<num>" },
},
})
local content = b:result()
-- バッファに適用
local buf = vim.api.nvim_create_buf(false, true)
local ns = vim.api.nvim_create_namespace("my_ns")
md.display_utils.apply_content_to_buffer(buf, ns, content)
-- 画像を表示(Kitty Graphics Protocol 対応ターミナルが必要)
-- ウィンドウを閉じると自動的にクリーンアップされます。
local win = vim.api.nvim_get_current_win()
md.display_utils.setup_images(win, content, ns)make testtests/*_test.lua にマッチする全テストファイルを nvim --headless で実行します。新しいテストファイルは自動的に検出されます。
MIT — LICENSE を参照。
