How can I preview markdown in Emacs in real time?

Solution 1:

There are a few solutions listed here: http://wikemacs.org/wiki/Markdown#Live_preview_as_you_type.

The pure-Emacs (nearly) solution and easy one, requiring no extra library from Python or Nodejs, is impatient-mode.

Impatient-mode

It's designed to work with html but the doc gives a trick to make it work with markdown. It also works like a charm but requires one configuration step:

  • Install impatient-mode with M-x package-install RET impatient-mode RET, given you have configured package.el to use the melpa repository.
  • Start an emacs' web server with M-x httpd-start.
  • Start impatient mode in the buffers you're interested to live preview: M-x impatient-mode.
  • Open your browser to localhost:8080/imp. You'll see the list of buffers with the mode enabled. Click on one: you see live rendering of the buffer.

To enable markdown conversion, we follow wikemacs:

  • Define this elisp function somewhere, like in your init file:

    (defun markdown-html (buffer)
      (princ (with-current-buffer buffer
        (format "<!DOCTYPE html><html><title>Impatient Markdown</title><xmp theme=\"united\" style=\"display:none;\"> %s  </xmp><script src=\"http://strapdownjs.com/v/0.2/strapdown.js\"></script></html>" (buffer-substring-no-properties (point-min) (point-max))))
      (current-buffer)))
    
  • Tell impatient mode to use it: M-x imp-set-user-filter RET markdown-html RET.

  • Go back to your browser, it works!

Flymd (not for FF>=68)

edit: thanks to the comments, flymd-fyit doesn't work in Firefox 68 and beyond.

Install it with package.el (M-x package-install RET flymd RET), then simply call M-x flymd-flyit. It opens the browser with the rendered markdown.

We can enable/disable auto-reloading and github markdown flavour.

edit: newer solutions, requiring an external package.

livedown-mode (with npm)

https://github.com/shime/emacs-livedown requires the livedown npm package. Also, this emacs package is not in MELPA, you have to clone it locally. Otherwise, it is a good and lightweight solution.

Vmd-mode (npm, Electron)

Another solution is vmd-mode, which works with the vmd node package. This is not the most heavy-weight solution: vmd is based on Electron (!).

Grip-mode (Python, Github's rate limit)

Another one is grip-mode, that relies on a Python package:

pip install --user grip

M-x package-install grip-mode

Then run M-x grip-mode in the markdown buffer. It opens a new tab in your browser.

Unfortunately, at the time of writing, it is limited by Github's rate limit. Indeed, to render content as precisely as Github, it calls its API. It doesn't render content locally. As such we are limited to 60 calls an hour, which is very few. See this issue: https://github.com/joeyespo/grip/issues/35

Solution 2:

I like this simpler approach that doesn't require another package nor a browser:

  • Execute M-x markdown-other-window on current buffer and display the result in other window.

  • Change to M-x html-mode and hide HTML tags M-x sgml-tags-invisible.

Then to update the html buffer run again markdown-other-window C-c C-c m on the markdown buffer.

Solution 3:

You can now do this in Spacemacs with markdown-live-preview-mode or SPC m c p.

Solution 4:

I would like recommend grip-mode: Instant Github-flavored Markdown/Org preview.

Solution 5:

Before following the steps in this answer, you would need to have a markdown parser installed on your system and a major mode to associate it to, in emacs.

Add emacs package repository to init.el

(require 'package)
(add-to-list 'package-archives
             '("melpa-stable" . "https://stable.melpa.org/packages/"))
(package-initialize)

Restart emacs and refresh packages:

M-x package-refresh-contents

Install emacs major mode markdown-mode by evaluating:

M-x package-install RET markdown-mode RET

Install markdown processor:

brew install pandoc
OR
sudo apt-get install pandoc

Map the markdown parser to the major-mode in ~/.emacs.d/init.ellike:

(custom-set-variables
  '(markdown-command "/usr/local/bin/pandoc"))