Syntax-highlighting markdown fenced code blocks in Emacs
Contents
The syntax-highlighted fenced code blocks in GitHub flavored markdown, or GFM, are a beautiful and useful invention. One starts a code block with three or more backticks or tildes, followed by the name of the language, and then proceeds to show one’s code, which, at least on GitHub, is then syntax highlighted.
In other words, something like this in your markdown:
```python def computer_says(no): print("computer says %s" % (no,)) ```
Would become this in the preview:
def computer_says(no): print("computer says %s" % (no,))
When I’m editing my markdown, I’d obviously like to see this language-specific highlighting interspersed with my normal markdown highlighting. SublimeText’s MarkdownEditing package does a superb job of this, but of course we’re currently rediscovering the universe that is Emacs.
DuckDuckGoing around, we run into at least two Emacs packages that do this: mmm-mode and polymode. We decided to try out both of them, finally ending up (quite happy) with the result shown in this screenshot:
polymode
After git cloning polymode into my ~/.emacs.d
, I installed it according to the instructions, by adding the following to my ~/.emacs.d/init.el
:
(setq load-path (append '("~/.emacs.d/polymode/" "~/.emacs.d/polymode/modes") load-path)) (require 'poly-R) (require 'poly-markdown)
Initially I had just the poly-markdown require, but that yielded an empty variable error. With this configuration, opening any .md file should activate the poly-markdown mode.
poly-markdown creates an indirect buffer for every code block that you create. This means if you switch buffers using for example C-x C-b
, you’ll see for each file you’re editing with poly-markdown as many extra buffers as there are fenced code blocks in your file.
When you start a new fenced code block, polymode picks this up automatically. When you load a new colour theme, the code blocks don’t always pick it up immediately, but this can be lived with.
mmm-mode
This all worked in my case, but I wanted to try out mmm-mode
as well. While not as hip and generic as polymode, this has been around for quite a while longer, and has seen much testing.
I installed mmm-mode from ELPA with M-x package-install RET mmm-mode
(yes, it’s that easy) and then changed my .emacs.d/init.el
as follows:
(require 'mmm-mode) (mmm-add-classes '((markdown-python :submode python-mode :face mmm-declaration-submode-face :front "^```python[\n\r]+" :back "^```$"))) (setq mmm-global-mode 't) (mmm-add-mode-ext-class 'markdown-mode nil 'markdown-python)
I’m only showing Python here, but I’ve defined classes and added them to markdown-mode
for JavaScript and emacs-lisp as well. There’s probably a better way to define the extra classes for a whole list of languages, but my (lack of) elisp skills doesn’t know about it yet.
conclusion
I definitely liked mmm-mode better. It doesn’t create all of those indirect buffers (which do affect my workflow). When you create a new fenced code block, it doesn’t highlight this until you do e.g. M-x mmm-parse-buffer
. However, I like this sort of determinism. Other than that, mmm-mode felt generally more stable and responsive than polymode. This no surprise; although polymode shows great potential, it’s still in alpha. Because I need something that works now, I’ll hold onto my mmm-mode for a while longer.