{"id":47635927,"url":"https://github.com/delphinus/md-render.nvim","last_synced_at":"2026-05-16T04:23:48.837Z","repository":{"id":344746468,"uuid":"1180690225","full_name":"delphinus/md-render.nvim","owner":"delphinus","description":"A Markdown rendering engine for Neovim — rich formatting, tables, images, video, Mermaid diagrams, and CJK-aware wrapping in floating windows","archived":false,"fork":false,"pushed_at":"2026-04-18T02:20:44.000Z","size":4757,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-18T04:26:32.724Z","etag":null,"topics":["floating-window","lua","markdown","markdown-renderer","neovim","neovim-plugin"],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/delphinus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T09:59:00.000Z","updated_at":"2026-04-18T02:20:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/delphinus/md-render.nvim","commit_stats":null,"previous_names":["delphinus/md-render.nvim"],"tags_count":81,"template":false,"template_full_name":null,"purl":"pkg:github/delphinus/md-render.nvim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delphinus%2Fmd-render.nvim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delphinus%2Fmd-render.nvim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delphinus%2Fmd-render.nvim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delphinus%2Fmd-render.nvim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/delphinus","download_url":"https://codeload.github.com/delphinus/md-render.nvim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delphinus%2Fmd-render.nvim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32082780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T06:27:27.065Z","status":"ssl_error","status_checked_at":"2026-04-21T06:27:21.250Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["floating-window","lua","markdown","markdown-renderer","neovim","neovim-plugin"],"created_at":"2026-04-02T00:05:37.258Z","updated_at":"2026-05-11T07:03:58.533Z","avatar_url":"https://github.com/delphinus.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# md-render.nvim\n\n[日本語版はこちら / Japanese version](README.ja.md) — Full Japanese/CJK support with kinsoku shori and BudouX phrase segmentation.\n\nA Markdown rendering engine for Neovim. Transforms raw Markdown into richly highlighted, interactive content — right inside your editor. Supports floating windows, tab views, and a pager mode for `less`-like usage from the command line.\n\n\u003cfigure align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/6c51f971-84bb-49fe-aaff-21db40712187\" width=\"900\" height=\"685\" alt=\"md-render.nvim showcase: inline formatting, tables, callouts, code blocks, images, video, and Mermaid diagrams\" /\u003e\n\u003c/figure\u003e\n\n## Highlights\n\n- **Rich inline formatting** — bold, strikethrough, inline code, links, Obsidian `==highlight==`, all rendered in-place\n- **Tables** — box-drawing borders, column alignment, proportional sizing, and inline formatting within cells\n- **Callouts \u0026 folds** — GitHub and Obsidian alert types with colored borders, icons, and click-to-toggle folding\n- **Code blocks** — fenced blocks with treesitter syntax highlighting; expandable when truncated\n- **Images** — local and web images (PNG, JPEG, WebP, GIF, animated GIF) displayed inline via terminal graphics protocol\n- **Video** — local and web video (MP4, WebM, MOV, AVI, MKV, M4V) played as animated frames inline\n- **Mermaid diagrams** — rendered as images inline\n- **CJK-aware word wrapping** — JIS X 4051 kinsoku shori + optional [BudouX](https://github.com/google/budoux) phrase segmentation via [budoux.lua](https://github.com/delphinus/budoux.lua)\n- **Clickable links** — mouse click to open URLs; OSC 8 hyperlink support for compatible terminals\n- **`\u003cdetails\u003e` support** — collapsible sections with click-to-toggle, respecting the `open` attribute\n- **Library API** — use the rendering engine programmatically from your own plugins\n\n\u003cfigure align=\"center\"\u003e\n  \u003cimg src=\"assets/screenshot-rendering.png\" width=\"672\" height=\"751\" alt=\"Inline formatting, tables, callouts, code blocks, and CJK line-breaking\" /\u003e\n  \u003cfigcaption\u003e\u003cem\u003eStatic preview: inline formatting, tables, callouts, code blocks, and CJK line-breaking\u003c/em\u003e\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n## Try it yourself\n\nThe repo bundles a showcase Markdown file demonstrating every feature. After cloning, view it with the pager:\n\n```bash\ngit clone https://github.com/delphinus/md-render.nvim\ncd md-render.nvim\nnvim +MdRenderPager assets/showcase.md\n```\n\nOr, once the plugin is installed, run `:MdRenderDemo` to see a built-in demo of every supported notation.\n\n## Requirements\n\n- Neovim \u003e= 0.10\n- For inline images and video: a terminal supporting the [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/).\n  Verified on [WezTerm](https://wezfurlong.org/wezterm/), [Kitty](https://sw.kovidgoyal.net/kitty/), and [Ghostty](https://ghostty.org/) (macOS/Linux).\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eOptional dependencies\u003c/strong\u003e\u003c/summary\u003e\n\n| Dependency | Purpose | Fallback |\n|---|---|---|\n| [curl](https://curl.se/) | Download web images and video | Custom function via `set_download_fn()` |\n| [FFmpeg](https://ffmpeg.org/) (`ffmpeg` / `ffprobe`) | JPEG/WebP → PNG conversion, animated GIF / video frame extraction | Falls back to ImageMagick (images only; video requires ffmpeg) |\n| [ImageMagick](https://imagemagick.org/) (`magick`) | JPEG/WebP → PNG, animated GIF frame extraction | `sips` (macOS) handles static conversion; animated GIF requires ffmpeg or magick |\n| [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli) (`mmdc`) | Render Mermaid diagrams as images | Falls back to `npx -y @mermaid-js/mermaid-cli` |\n| [budoux.lua](https://github.com/delphinus/budoux.lua) | CJK phrase-level line breaking (BudouX) | Character-level splitting (kinsoku rules still apply) |\n| Treesitter parsers | Syntax highlighting in code blocks | Code blocks rendered without highlighting |\n| [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) or [mini.icons](https://github.com/echasnovski/mini.icons) | File type icons in code block headers | Built-in icon table |\n\nFor image/video format conversion and animation support, the plugin tries tools in this order:\n\n| Use case | 1st | 2nd | 3rd |\n|---|---|---|---|\n| Static image conversion (JPEG/WebP → PNG) | `sips` (macOS) | `ffmpeg` | `magick` |\n| Animated GIF frame extraction | `ffmpeg` | `magick` | — |\n| Video frame extraction | `ffmpeg` | — | — |\n\n\u003c/details\u003e\n\n## Installation\n\n### lazy.nvim\n\n```lua\n{\n  \"delphinus/md-render.nvim\",\n  version = \"*\",\n  dependencies = {\n    { \"nvim-tree/nvim-web-devicons\", version = \"*\" }, -- optional: file type icons in code blocks\n    { \"delphinus/budoux.lua\", version = \"*\" }, -- optional: CJK phrase-level line breaking\n  },\n  keys = {\n    { \"\u003cleader\u003emp\", \"\u003cPlug\u003e(md-render-preview)\",     desc = \"Markdown preview (toggle)\" },\n    { \"\u003cleader\u003emt\", \"\u003cPlug\u003e(md-render-preview-tab)\", desc = \"Markdown preview in tab (toggle)\" },\n    { \"\u003cleader\u003emd\", \"\u003cPlug\u003e(md-render-demo)\",        desc = \"Markdown render demo\" },\n  },\n}\n```\n\n### vim.pack (Neovim 0.12+)\n\n```lua\nvim.pack.add({\n  \"https://github.com/delphinus/md-render.nvim\",\n  -- optional:\n  \"https://github.com/nvim-tree/nvim-web-devicons\",\n  \"https://github.com/delphinus/budoux.lua\",\n})\n```\n\n### mini.deps\n\n```lua\nlocal add = MiniDeps.add\nadd({\n  source = \"delphinus/md-render.nvim\",\n  depends = {\n    \"nvim-tree/nvim-web-devicons\", -- optional\n    \"delphinus/budoux.lua\",        -- optional\n  },\n})\n```\n\n## Comparison with similar plugins\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eWhy not other Markdown previewers?\u003c/strong\u003e\u003c/summary\u003e\n\n- **[markdown-preview.nvim](https://github.com/iamcco/markdown-preview.nvim)** — Excellent for true browser-quality rendering, but requires a browser context. md-render runs entirely inside the terminal.\n- **[render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)** — Beautiful in-buffer rendering, but modifies the editing buffer itself. md-render keeps your editing buffer untouched and renders into a separate floating/tab window or pager view.\n- **[mcat](https://github.com/Skardyy/mcat)** — Closest in spirit (a pure-terminal Markdown renderer), but lacks complex layout features like auto-folding tables, click-to-toggle folds, and CJK word wrapping.\n\nmd-render.nvim aims to be a dedicated previewer that runs entirely in the terminal, with rich layout support and first-class CJK handling.\n\n\u003c/details\u003e\n\n## Keymaps\n\nThe plugin provides `\u003cPlug\u003e` mappings but does **not** set any default keybindings. Map them yourself:\n\n```lua\nvim.keymap.set(\"n\", \"\u003cleader\u003emp\", \"\u003cPlug\u003e(md-render-preview)\",     { desc = \"Markdown preview (toggle)\" })\nvim.keymap.set(\"n\", \"\u003cleader\u003emt\", \"\u003cPlug\u003e(md-render-preview-tab)\", { desc = \"Markdown preview in tab (toggle)\" })\nvim.keymap.set(\"n\", \"\u003cleader\u003emd\", \"\u003cPlug\u003e(md-render-demo)\",        { desc = \"Markdown render demo\" })\n```\n\n| `\u003cPlug\u003e` mapping | Description |\n|---|---|\n| `\u003cPlug\u003e(md-render-preview)` | Toggle a floating preview window for the current Markdown buffer |\n| `\u003cPlug\u003e(md-render-preview-tab)` | Toggle a tab preview for the current Markdown buffer |\n| `\u003cPlug\u003e(md-render-toggle)` | Toggle the current window between source and render mode in place |\n| `\u003cPlug\u003e(md-render-auto)` | **[experimental]** Toggle auto mode (render outside Insert) for the current buffer |\n| `\u003cPlug\u003e(md-render-split)` | Open a split showing source and rendered Markdown |\n| `\u003cPlug\u003e(md-render-demo)` | Show a demo window with all supported Markdown notations |\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `:MdRender` | Toggle a floating preview window |\n| `:MdRenderTab` | Toggle a tab preview |\n| `:MdRenderToggle` | Toggle the current window between source and render mode in place |\n| `:MdRenderAuto [on\\|off]` | **[experimental]** Auto-toggle source/render based on Insert mode (per buffer) |\n| `:MdRenderSplit` | Open a split showing source and rendered Markdown |\n| `:MdRenderPager` | Pager mode — full-screen, no chrome, `q` to quit Neovim |\n| `:MdRenderDemo` | Show a demo window with all supported Markdown notations |\n\n### In-place toggle\n\n`:MdRenderToggle` swaps the current window between the source Markdown buffer and a rendered view of it — without opening a new tab or floating window. This is designed for split layouts where you want, for example, code in one split and the rendered README in the other.\n\n```vim\n:vsplit README.md\n:MdRenderToggle\n```\n\nBehavior:\n\n- The render buffer is **read-only** and reused across toggles (one render buffer per source).\n- When the same source is shown in multiple windows, only the invoking window swaps; edits from other windows are reflected on the next toggle into render mode.\n- Cursor position round-trips between source and render via the source-line mapping.\n- `number`, `relativenumber`, and `list` are turned off on render-mode windows. The originals are stashed on the window and restored when toggling back to source.\n- Inside render mode, `q` / `\u003cEsc\u003e` / `\u003cCR\u003e` are **not** bound to close — call `:MdRenderToggle` again to return to source mode. `\u003cLeftMouse\u003e` still toggles folds, expands regions, and opens links.\n\n### Auto-toggle on Insert mode (experimental)\n\n\u003e **Experimental.** This feature is new and the UX may change. Please report issues or rough edges.\n\n`:MdRenderAuto on` keeps the current buffer in render mode while in Normal mode and swaps back to source automatically when you start editing. Pass `off` to disable, or call without arguments to toggle. To opt every Markdown buffer in:\n\n```vim\nautocmd FileType markdown silent! MdRenderAuto on\n```\n\nSee `:help :MdRenderAuto` for behavior details — the `i` / `I` / `a` / `A` / `o` / `O` remaps, `:w` forwarding, and the editing operations that are blocked on the read-only render buffer.\n\n### Source/render split\n\n\u003cfigure\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/24999fe8-9ff0-4ca3-9bd1-b72ec5d7f33c\" width=\"407\" height=\"328\" alt=\"Source/render split\" /\u003e\n  \u003cfigcaption\u003e\u003cem\u003eSource/render split — edits propagate live, including inline images\u003c/em\u003e\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n`:MdRenderSplit` opens a split showing the source buffer and the rendered view together. Direction follows standard Vim split modifiers:\n\n- `:MdRenderSplit` — horizontal split\n- `:vert MdRenderSplit` — vertical split (typical \"README + code\" layout)\n- `:topleft MdRenderSplit` — place at the top\n- `:botright MdRenderSplit` — place at the bottom\n\nEdits to the source propagate live, and cursor/scroll position is synchronized in both directions. See `:help :MdRenderSplit` for full behavior and the inline-image limitation.\n\n### Pager mode\n\n\u003cfigure\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/3c8d94a2-7a7d-4d99-ac9c-1b69870fee67\" width=\"682\" height=\"446\" alt=\"Pager mode\" /\u003e\n  \u003cfigcaption\u003e\u003cem\u003ePager mode — browse Markdown like \u003ccode\u003eless\u003c/code\u003e\u003c/em\u003e\u003c/figcaption\u003e\n\u003c/figure\u003e\n\nUse `MdRenderPager` to view Markdown files like `less`:\n\n```bash\nnvim +MdRenderPager README.md\n```\n\nAdd a shell alias for convenience:\n\n```bash\nalias mdless='nvim +MdRenderPager'\nmdless README.md\n```\n\n## Telescope Integration\n\n\u003cfigure\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/29fff5f5-d437-46d7-b92c-3d1a4bb21dd8\" width=\"472\" height=\"457\" alt=\"Telescope integration\" /\u003e\n  \u003cfigcaption\u003e\u003cem\u003eTelescope previewer with md-render\u003c/em\u003e\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n### Previewer\n\n`require(\"md-render.telescope\").previewer()` creates a previewer that can be\npassed to any [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\npicker — builtin, extension, or custom:\n\n```lua\nlocal previewer = require(\"md-render.telescope\").previewer()\n\nrequire(\"telescope.builtin\").find_files({ previewer = previewer })\nrequire(\"telescope\").extensions.egrepify.egrepify({ previewer = previewer })\n```\n\nThe previewer automatically handles three kinds of files:\n\n| File type | Behavior |\n|---|---|\n| Markdown (`.md`, `.markdown`) | Full md-render rendering with highlights, links, and images |\n| Image / Video (PNG, JPEG, WebP, GIF, MP4, ...) | Inline display via Kitty graphics protocol |\n| Other files | Falls back to telescope's default previewer with syntax highlighting |\n\nFor grep-based pickers, the preview scrolls to the matched line.\n\n### `:Telescope md_render` Extension\n\nA shortcut for builtin pickers. Wraps `telescope.builtin` pickers with the\nmd-render previewer. All arguments are passed through:\n\n```vim\n:Telescope md_render find_files\n:Telescope md_render live_grep cwd=~/notes\n:Telescope md_render grep_string search=TODO\n```\n\n## Snacks.nvim Integration\n\n`require(\"md-render.snacks\").preview()` creates a preview function for\n[snacks.nvim](https://github.com/folke/snacks.nvim) pickers. It handles the\nsame three file types as the telescope previewer (Markdown, image/video, and\nfallback).\n\nConfigure it globally to apply to all pickers:\n\n```lua\nrequire(\"snacks\").setup({\n  picker = {\n    preview = require(\"md-render.snacks\").preview(),\n  },\n})\n```\n\nOr per-source:\n\n```lua\nrequire(\"snacks\").setup({\n  picker = {\n    sources = {\n      files = { preview = require(\"md-render.snacks\").preview() },\n      grep = { preview = require(\"md-render.snacks\").preview() },\n    },\n  },\n})\n```\n\n## FAQ / Troubleshooting\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eImages don't show — only their alt text or filenames appear\u003c/strong\u003e\u003c/summary\u003e\n\nInline image display requires a terminal that supports the [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/). Verify you're using **WezTerm**, **Kitty**, or **Ghostty**. tmux and other multiplexers may strip the image escape sequences unless explicitly configured to pass them through.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eVideos appear as a single static frame\u003c/strong\u003e\u003c/summary\u003e\n\nVideo frame extraction requires `ffmpeg` to be installed and available in `$PATH`. Without it, the plugin falls back to displaying just the first frame as a still image. Install it via your package manager (e.g. `brew install ffmpeg`).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eMermaid diagrams don't render\u003c/strong\u003e\u003c/summary\u003e\n\nMermaid rendering requires the `mmdc` binary from [@mermaid-js/mermaid-cli](https://github.com/mermaid-js/mermaid-cli). If `mmdc` isn't installed globally, the plugin falls back to `npx -y @mermaid-js/mermaid-cli`, which is significantly slower on first invocation. Install it globally with `npm install -g @mermaid-js/mermaid-cli` for faster rendering.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eJapanese text wrapping looks unnatural\u003c/strong\u003e\u003c/summary\u003e\n\nBy default, md-render applies JIS X 4051 kinsoku shori (forbidden line-break rules) at the character level. For phrase-level segmentation that respects natural word boundaries in Japanese, install [budoux.lua](https://github.com/delphinus/budoux.lua) — the plugin will automatically detect and use it.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCode blocks have no syntax highlighting\u003c/strong\u003e\u003c/summary\u003e\n\nSyntax highlighting requires the corresponding treesitter parser to be installed. For example, to highlight Lua code blocks, install the `lua` parser via `:TSInstall lua` (with [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter)) or via Neovim 0.11+'s built-in parser management.\n\n\u003c/details\u003e\n\n## Usage as a library\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eProgrammatic API\u003c/strong\u003e\u003c/summary\u003e\n\nUse the rendering engine to build highlighted content programmatically:\n\n```lua\nlocal md = require(\"md-render\")\n\n-- Render a single line of markdown\nlocal text, highlights, links = md.Markdown.render(\"**bold** and [link](https://example.com)\")\n\n-- Build full document content\nlocal ContentBuilder = md.ContentBuilder\nlocal b = ContentBuilder.new()\nb:render_document(lines, {\n  max_width = 80,\n  indent = \"  \",\n  repo_base_url = \"https://github.com/user/repo\",\n  autolinks = {\n    { key_prefix = \"JIRA-\", url_template = \"https://jira.example.com/browse/JIRA-\u003cnum\u003e\" },\n  },\n})\nlocal content = b:result()\n\n-- Apply to a buffer\nlocal buf = vim.api.nvim_create_buf(false, true)\nlocal ns = vim.api.nvim_create_namespace(\"my_ns\")\nmd.display_utils.apply_content_to_buffer(buf, ns, content)\n\n-- Display images (requires a Kitty Graphics Protocol compatible terminal)\n-- Images are automatically cleaned up when the window is closed.\nlocal win = vim.api.nvim_get_current_win()\nmd.display_utils.setup_images(win, content, ns)\n```\n\n\u003c/details\u003e\n\n## Development\n\n### Running Tests\n\n```bash\nmake test\n```\n\nThis runs all `tests/*_test.lua` files via `nvim --headless`. New test files matching the `*_test.lua` pattern are picked up automatically.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelphinus%2Fmd-render.nvim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdelphinus%2Fmd-render.nvim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelphinus%2Fmd-render.nvim/lists"}