Built using GLSP and Goldmark, and heavily inspired by mdpls
Markdown Preview Language Server (mpls
) is a language server designed to
enhance your Markdown editing experience. With live preview in the browser,
mpls
allows you to see your Markdown content rendered in real-time. Whether
you're writing documentation or creating notes, mpls
provides a seamless and
interactive environment.
Built with terminal editors in mind, such as (Neo)vim and Helix, which do not
have built-in Markdown rendering, mpls
bridges the gap by providing a live
preview feature that works alongside these editors. Additionally, mpls
is
compatible with any editor that supports the Language Server Protocol (LSP),
making it a versatile tool for Markdown editing across various platforms. For
users of Visual Studio Code, there is also a dedicated extension available at
mpls-vscode-client,
- Live Preview: Instantly see your Markdown changes reflected in the browser.
mpls
is built using Goldmark, a Markdown
parser written in Go. Goldmark is known for its extensibility and performance,
making it an ideal choice for mpls
.
mpls
utilizes several of Goldmark's extensions to enhance the Markdown
rendering experience:
Always enabled
- Github Flavored Markdown: Goldmark's built in GFM extension ensures Table, Strikethrough, Linkify and TaskList elements are displayed correctly.
- Image Rendering: The img64 extension allows for seamless integration of images within your Markdown files.
- Math Rendering: The katex
extension enables the rendering of LaTeX-style mathematical expressions using
KaTeX. Please note that the KaTeX extension requires
cgo
and will only be included ifmpls
is built withCGO_ENABLED=1
. This option is not enabled for the prebuilt binaries. - Metadata: The meta extension parses metadata in YAML format.
- Syntax highlighting: The highlighting extension adds syntax-highlighting to the fenced code blocks.
Optional
- Emoji: The emoji extension enables emoji support.
- Footnotes: The footnote extension enables footnotes.
- Wikilinks rendering: The wikilink extension enables parsing and rendering of [[wiki]] -style links. (Note: image preview does not work for wikilinks)
If you want a new Goldmark extension added to mpls
please look
here.
mpls
supports the display of diagrams and flowcharts by integrating
Mermaid.js, a powerful JavaScript library for
generating diagrams from text definitions.
mpls
supports PlantUML, a powerful tool for creating
UML diagrams from plain text descriptions. This integration allows you to easily
embed PlantUML code in your markdown files. Diagrams are rendered upon saving
and only if the UML code has changed.
Please note that external HTTP calls are made only when UML code is present in
the markdown and has changed, as well as when a file is opened. For users
concerned about security, you can host a PlantUML server locally and specify the
--plantuml-server
flag to ensure that no external calls are made.
If you already have go installed you can just run:
go install github.com/mhersson/mpls@latest
If not, the easiest way to install mpls
is to download one of the prebuilt
release binaries. You can find the latest releases on the
Releases page.
-
Download the appropriate tar.gz file for your operating system.
-
Extract the contents of the tar.gz file. You can do this using the following command in your terminal:
tar -xzf mpls_<version>_linux_amd64.tar.gz
(Replace
<version>
with the actual version of the release.) -
Copy the extracted binary to a directory that is in your system's PATH. For example:
sudo cp mpls /usr/local/bin/
Build From Source
If you otherwise prefer to build manually from source, if you want the KaTeX math extension, or if no prebuilt binaries are available for your architecture, follow these steps:
-
Clone the repository:
git clone https://github.com/mhersson/mpls.git cd mpls
-
Build the project:
You can build the project using the following command:
To include the math extension, you need to set
CGO_ENABLED=1
before running this command:make build
This command will compile the source code and create an executable.
-
Install the executable:
You have two options to install the executable:
-
Option 1: Copy the executable to your PATH:
After building, you can manually copy the executable to a directory that is in your system's PATH. For example:
sudo cp mpls /usr/local/bin/
-
Option 2: Use
make install
if you are using GOPATH:If the GOPATH is in your PATH, you can run:
make install
This will install the executable to your
$GOPATH/bin
directory.
-
Verify the installation:
After installation, you can verify that mpls
is installed correctly by
running:
mpls --version
This should display the version of the mpls
executable.
The following options can be used when starting mpls
:
Flag | Description |
---|---|
--browser |
Specify web browser to use for the preview. (1) |
--code-style |
Sets the style for syntax highlighting in fenced code blocks. (2) |
--dark-mode |
Enable dark mode |
--enable-emoji |
Enable emoji support |
--enable-footnotes |
Enable footnotes |
--enable-wikilinks |
Enable rendering of [[wiki]] -style links |
--full-sync |
Sync the entire document for every change being made. (3) |
--no-auto |
Don't open preview automatically |
--plantuml-disable-tls |
Disable encryption on requests to the PlantUML server |
--plantuml-server |
Specify the host for the PlantUML server |
--plantuml-path |
Specify the base path for the PlantUML server |
--port |
Set a fixed port for the preview server |
--version |
Displays the mpls version. |
--help |
Displays help information about the available options. |
- On Linux specify executable e.g "firefox" or "google-chrome", on MacOS name of Application e.g "Safari" or "Microsoft Edge", on Windows use full path. On WSL, specify the executable as "explorer.exe" to start the default Windows browser.
- The goldmark-highlighting extension use
Chroma as the syntax highlighter, so
all available styles in Chroma are available here. Default style is
catppuccin-mocha
. - Has a small impact on performance, but makes sure that commands like
reflow
in Helix, does not impact the accuracy of the preview. Additionally, it disablesmpls'
efforts to scroll to the closest section header when editing.
Helix
languages.toml
# Configured to run alongside marksman.
[[language]]
auto-format = true
language-servers = ["marksman", "mpls"]
name = "markdown"
[language-server.mpls]
command = "mpls"
args = ["--dark-mode", "--enable-emoji"]
# An example args entry showing how to specify flags with values:
# args = ["--port", "8080", "--browser", "google-chrome"]
Neovim (LazyVim)
lua/plugins/mpls.lua
return {
{
"neovim/nvim-lspconfig",
opts = {
servers = {
mpls = {},
},
setup = {
mpls = function(_, opts)
local lspconfig = require("lspconfig")
local configs = require("lspconfig.configs")
if not configs.mpls then
configs.mpls = {
default_config = {
cmd = { "mpls", "--dark-mode", "--enable-emoji" },
filetypes = { "markdown" },
single_file_support = true,
root_dir = function(startpath)
local git_root = vim.fs.find(".git", { path = startpath or
vim.fn.getcwd(), upward = true })
return git_root[1] and vim.fs.dirname(git_root[1]) or startpath
end,
settings = {},
},
docs = {
description = [[https://github.com/mhersson/mpls
Markdown Preview Language Server (MPLS) is a language server that provides
live preview of markdown files in your browser while you edit them in your favorite editor.
]],
},
}
end
lspconfig.mpls.setup(opts)
vim.api.nvim_create_user_command('MplsOpenPreview', function()
local clients = vim.lsp.get_active_clients()
local mpls_client = nil
for _, client in ipairs(clients) do
if client.name == "mpls" then
mpls_client = client
break
end
end
-- Only execute the command if the MPLS client is found
if mpls_client then
local params = {
command = 'open-preview',
arguments = {}
}
mpls_client.request('workspace/executeCommand', params,
function(err, result)
if err then
print("Error executing command: " .. err.message)
end
end)
else
print("mpls is not attached to the current buffer.")
end
end, {})
end,
},
},
},
}
Doom-Emacs with lsp-mode
config.el
(after! markdown-mode
;; Auto start
(add-hook 'markdown-mode-local-vars-hook #'lsp!))
(after! lsp-mode
(defgroup lsp-mpls nil
"Settings for the mpls language server client."
:group 'lsp-mode
:link '(url-link "https://github.com/mhersson/mpls"))
(defun mpls-open-preview ()
"Open preview of current buffer"
(interactive)
(lsp-request
"workspace/executeCommand"
(list :command "open-preview")))
(defcustom lsp-mpls-server-command "mpls"
"The binary (or full path to binary) which executes the server."
:type 'string
:group 'lsp-mpls)
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection
(lambda ()
(list
(or (executable-find lsp-mpls-server-command)
(lsp-package-path 'mpls)
"mpls")
"--dark-mode"
"--enable-emoji"
)))
:activation-fn (lsp-activate-on "markdown")
:initialized-fn (lambda (workspace)
(with-lsp-workspace workspace
(lsp--set-configuration
(lsp-configuration-section "mpls"))
))
;; Priority and add-on? are not needed,
;; but makes mpls work alongside other lsp servers like marksman
:priority 1
:add-on? t
:server-id 'mpls))
;; Send mpls/editorDidChangeFocus events
(defvar last-focused-markdown-buffer nil
"Tracks the last markdown buffer that had focus.")
(defun send-markdown-focus-notification ()
"Send an event when focus changes to a markdown buffer."
(when (and (eq major-mode 'markdown-mode)
(not (eq (current-buffer) last-focused-markdown-buffer))
lsp--buffer-workspaces)
(setq last-focused-markdown-buffer (current-buffer))
;; Get the full file path and convert it to a URI
(let* ((file-name (buffer-file-name))
(uri (lsp--path-to-uri file-name)))
;; Send notification
(lsp-notify "mpls/editorDidChangeFocus"
(list :uri uri
:fileName file-name)))))
(defun setup-markdown-focus-tracking ()
"Setup tracking for markdown buffer focus changes."
(add-hook 'buffer-list-update-hook
(lambda ()
(let ((current-window-buffer (window-buffer (selected-window))))
(when (and (eq current-window-buffer (current-buffer))
(eq major-mode 'markdown-mode)
(buffer-file-name))
(send-markdown-focus-notification))))))
;; Initialize the tracking
(setup-markdown-focus-tracking))