Repository navigation
Releases: selimacerbas/mdkite.nvim
Release list
v2.1.0
Added
- A buffer whose filetype is dotted with a
markdownpart, such asrzk.markdownfor a literate file, previews whole as Markdown with no config, since Neovim reads a dotted filetype as each of its parts in turn; before, only the filetypemarkdowndid. Thanks @ddxtanx (#32). filetypesoption: filetypes with nomarkdownpart, such as{ "quarto", "rmd" }, preview whole as Markdown too. The list adds tomarkdownand never replaces it. A value that is not a list of filetype names is refused bysetup()with one error,mdkite: filetypes takes a list of filetype names, such as { "quarto" }; setup changed nothing, and that call applies nothing. Thanks @ddxtanx (#32).
v2.0.0
Upgrading from markdown-preview.nvim
The plugin is mdkite.nvim from this release, and the server it runs on is kitehost.nvim, live-server.nvim's name from its v2.0.0, which this release requires. Through 2.x the former lazy.nvim spec still installs it, since GitHub redirects the repository's former name; the former module and commands still work, each warning once a session and naming its replacement, and the former opt-out global still opts out. All three are removed in 3.0.0. Everything else in the table takes the new name now.
| What | Before 2.0.0 | From 2.0.0 |
|---|---|---|
| Repository and lazy.nvim spec | selimacerbas/markdown-preview.nvim |
selimacerbas/mdkite.nvim |
| Server dependency | selimacerbas/live-server.nvim |
selimacerbas/kitehost.nvim, v2.0.0 or newer |
| Module | require("markdown_preview") |
require("mdkite") |
| Commands | :MarkdownPreview, :MarkdownPreviewRefresh, :MarkdownPreviewStop |
:MdKite with start, refresh and stop, one for each former command in that order, and the new toggle, completed by <Tab>, none taking an argument; a bare :MdKite runs start |
| Notices | Markdown Preview: ... |
mdkite: ... on every notice this plugin makes (the server's own notices begin kitehost:), but a deprecation warning, which is Neovim's own text (:MarkdownPreview is deprecated, use :MdKite start instead.) |
| Cache directory | stdpath("cache")/markdown-preview |
stdpath("cache")/mdkite |
| Opt-out global | vim.g.loaded_markdown_preview |
vim.g.loaded_mdkite; the former one still opts out |
| Auto-refresh augroup | MarkdownPreviewAuto |
MdKiteAuto |
| Browser console prefix | [markdown-preview] |
[mdkite] |
| Page title | Markdown Preview |
mdkite |
In takeover mode, a preview of a release before 2.0.0 still running in another Neovim keeps its lock under the former cache directory: a start names it and its port in one error, starts nothing beside it and writes nothing under that directory.
A lazy.nvim spec that relies on opts or config = true and is named after neither repository (a name or dir of its own, or a fork under another name) sets main = "mdkite": two top-level modules ship through 2.x, mdkite and markdown_preview, so lazy.nvim cannot choose the one its opts go to and reports Lua module not found for config of <name>. The new spec, the former one, a fork that keeps the name mdkite.nvim and a spec with its own config function need none.
Added
lazy.lua: lazy.nvim installs kitehost.nvim from this plugin's own declaration, so a spec with nodependenciesline still gets it.:MdKite togglestarts the preview, or stops the one running, a joined one included.
Changed
- BREAKING: The plugin runs on kitehost.nvim v2.0.0 or newer (the upgrading section above). With an older server on the runtimepath, or none, a start refuses with one error,
mdkite: requires kitehost.nvim v2.0.0 or newer; install or update selimacerbas/kitehost.nvim, where a missing server raised a Lua error as the plugin loaded. Each start looks for the server again until it finds one, so one put on the runtimepath after the plugin loaded is used. - A kitehost.nvim without a capability the plugin requires,
server.features.host_check(the Host check that keeps a DNS-rebinding page from the token the loopback page carries) orserver.features.start_raises, is refused at start the same way, with one error naming the floor and the flag it lacks,mdkite: requires kitehost.nvim v2.0.0 or newer, and the installed one lacks features.host_check; update selimacerbas/kitehost.nvim, where a server without the asset route was only warned about. - The start-failure notification reads
mdkite: failed to start server (port <port>): <reason>. vim.uvreplaces the deprecatedvim.loopthroughout.- When the port is taken by another program, the start-failure notification says so and how to pick another:
mdkite: port <port> is in use by another program. Set port to a free one in setup(), or port = 0 with instance_mode = "multi" for an OS-assigned port.A port the OS assigns keeps the generic notification, whose reason names the port. - When the server binds
127.0.0.1(the defaulthost, and what"localhost"binds), the preview URL no longer carries the?t=token; a server bound to any other address keeps it. The address the server bound decides, not thehostsetting:"localhost"openshttp://127.0.0.1:<port>/, since a browser trieslocalhost's::1first, and a takeover secondary follows the address the primary's lock records. The URL is what lands in browser history, its sync and the process list, so the token stays out of all three.
Removed
- BREAKING: Neovim 0.9, which the README listed as supported. Every release since v1.0.0 needed Neovim 0.10 and failed at first use on 0.9; the requirement is now checked at load, so on 0.9 the plugin shows one notification, "mdkite: requires Neovim 0.10 or newer", and every command refuses with the same message.
- The unreferenced 7 MB demo gif, so a fresh checkout is smaller.
Fixed
- A takeover-mode lock file that cannot be made private fails the start with the start-failure notification; before, the server stayed running with an empty lock and the start raised a Lua error.
- A preview that fails to start (a taken port, an address kitehost cannot bind, a lock file that cannot be made private) keeps no autocmds, no session token and no workspace pointer, and drops a takeover role it held as a secondary; before, six autocmds kept refreshing a preview that did not exist.
- When kitehost refuses to switch the preview to another buffer, the notice reads
mdkite: could not retarget: <reason>and the preview keeps showing the buffer it showed, its text and images included. When the server reports file watching off after a switch, a warning says that changes made outside this editor may not refresh the preview. A reload or scroll update kitehost refuses is reported once per preview server. Before, all three went unreported. - An IPv6
hostsuch as"::1", withinstance_mode = "multi", gives a preview URL in brackets,http://[::1]:<port>/?t=<token>, which browsers open; the token stays, since only a127.0.0.1bind's page carries it. The IPv6 wildcard"::", however it is spelled, showshttp://[::1]:<port>/?t=<token>, as kitehost.nvim does, and an IPv4-mapped address such as"::ffff:127.0.0.1"shows its IPv4 form. - When a second Neovim fails to start a takeover preview on the port another Neovim's preview holds (its check for the running preview timed out, say), the running preview keeps serving its own buffer and keeps its lock file, and the notification adds that another Neovim's preview may hold the port; before, the second instance overwrote the preview's files with its own buffer and a token the server refuses, and removed the lock.
- A takeover start joins another Neovim's preview only while the process its lock names runs and the server on the lock's port takes the lock's token and refuses a request without one; before, anything listening on that port counted, so a start could join a crashed preview's lock whose port another program had since taken and send that program its scroll updates, token included.
- A session token that cannot be made fails the start with one error notification, before any server starts. A failure after the preview server started (the preview's files, the lock file, an
auto_refresh_eventsentry Neovim does not know) stops the server and shows one error notification with the reason and no Lua source position; before, the server kept running and the start raised a Lua error. The same holds when joining another Neovim's preview, when the workspace directory cannot be created, and when switching buffers, where a failed switch returns the preview to the buffer it showed. A write that fails no longer empties the file the preview serves, and a lock file whose port is not a valid port is treated as absent. - Changing
hostwithsetup()while a preview runs no longer makes the next:MdKite starton another buffer refuse; the new host applies to the next start. - A Neovim that joined another's takeover preview reports a scroll update the running preview refuses (after a restart with a new token) or cannot receive (the preview is gone) once, and again after
:MdKite startjoins anew; before, it said nothing. - Stopping the preview within 200 ms of starting it or switching buffers no longer raises a Lua error from the pending browser open, and no browser opens for the stopped preview.
- On Windows, when the runtimepath lists no copy of the preview page the plugin ships, a start finds it from the plugin's own path whichever slash that path is written with; before, a path written with forward slashes failed the start with
Could not locate assets/index.html in runtimepath.
Security
- The takeover-mode lock file is made private (mode 0600) on the open file before the session token is written to it, whatever the file was before; the open's own mode applies only to a file it creates. No released version left the token readable by others: a start has removed the lock before every write since the token joined it in v1.8.0, and the 0644 lock files of v1.7.0 and earlier held no token. The loopback preview page still carries the token (SECURITY.md).
v1.10.0
Features
- Relative images —
next to your markdown file now renders in the preview, via a token-gated asset route resolved against the source file's directory (#17). Requires live-server.nvim v1.5.0+. - Network access — new
hostoption (default127.0.0.1); set"0.0.0.0"to view the preview from another machine, e.g. over SSH. Thanks @icyveins7 (#28, #30). - Custom CSS — new
custom_cssoption layers your stylesheet over the bundled styles (supports~and$VAR). Thanks @y2w8 (#21). - YAML front matter — shown in a collapsible panel and stripped from the render by default; configurable via
yaml_mode("panel"/"hide"/"raw"). Closes #18. Based on work by @Al3cLee (#20). allow_raw_htmloption — setfalseto render embedded HTML as plain text when previewing untrusted markdown (#27).- WSL — browser launch now tries
wslview→explorer.exe→powershell.exe, and surfaces the preview URL if none work (#26).
Fixes
- Task-list checkboxes now render (the plugin was loaded under the wrong global name). Thanks @tcuthbert (#25).
- Preview no longer gets stuck on "Waiting for content…" after a Neovim restart — the token placeholder collided with a JS sentinel and broke auth on tab reuse (#31).
- Code-block language badge and copy button stay pinned while scrolling wide code, and no longer reset scroll position on live updates. Based on work by @Al3cLee (#20).
- Mermaid diagrams fit one page when printing to PDF. Thanks @harish2704 (#29).
Security
- Removed a stale
cors = truethat emittedAccess-Control-Allow-Origin: *, which could let any website read the auth token cross-origin. - On a non-loopback
host, the token is no longer baked into the served page and the preview page itself is token-gated (the browser bootstraps from the?t=URL). - New Security section in the README covering the token model, raw-HTML trade-off, CDN loading, and network-bind exposure.
Note: relative-image support needs live-server.nvim v1.5.0+; the plugin warns once if the installed version is older.
v1.9.0
- Feature: Lifecycle hooks via
setup({ hooks = { on_start = fn, on_stop = fn } }).on_start(url)runs after the preview is ready and receives the full URL (with the auth token included), useful whenopen_browser = false.on_stop()runs after the server stops and cleanup completes. Both default tonil. (#24, thanks @gogongxt)
v1.8.0
- Feature:
default_theme = "dark" | "light"config option to set the initial preview theme. The in-browser sun/moon toggle still works after page load. Closes #19. (#16, thanks @gogongxt) - Feature:
mermaid_elk = trueenables the ELK layout engine for mermaid diagrams, producing cleaner layouts for medium and large flowcharts and class diagrams. Off by default (adds ~800 KB CDN fetch). Enable per-diagram with%%{init: {"layout": "elk"}}%%. (#22, thanks @fuzzybear3) - Security: Token auth on
content.mdand the live-reload control endpoints. A 128-bit token is generated at server start, threaded through the auto-opened browser URL, and stashed insessionStorage. No user-facing config needed. (#23) - Requires:
live-server.nvimv1.4.0+for the token auth feature. If you pin versions, upgrade both together. Lazy.nvim users onbranch = "main"orversion = "*"are fine.
v1.7.0
- Feature:
browserconfig option to override the system default browser (#11)browser = nil(default): system defaultbrowser = "Firefox": browser by app/binary name (macOS usesopen -a)browser = { "google-chrome", "--incognito" }: full command with args
v1.6.0
- Fix: overlay zoom-in no longer cuts off content. The fullscreen mermaid viewer now properly scrolls when zoomed beyond the viewport (#11)
- Feature:
bottom_paddingconfig option (0–1 fraction) controls how far the last line can scroll. Default 0.5 means the final line scrolls to the viewport midpoint (#12) - Feature: WSL support — the preview now opens via
explorer.exeon Windows Subsystem for Linux (#14)
v1.5.3
- Strip YAML front matter from preview — metadata blocks no longer render as headings/text
v1.5.2
- Add task list checkbox rendering (
- [ ]/- [x]) via markdown-it-task-lists
v1.5.1
- Remove heading anchor permalink symbols (#) from preview for cleaner readability