Using Kramdown instead of Maruku
Update January 23rd, 2015: Paul Robert Lloyd improved the converter with his Pypedown plugin. It also sports the Typogruby extension for some visual juice.
Update July 24th, 2014: Matthijs van den Bos improved Juan’s plugin to work with Jekyll 2.x.
Update May 7th, 2014: As of Jekyll version 2.0.0, Kramdown is Jekyll’s default Markdown converter. However, it’s still using CodeRay.
Update August 14th, 2013: The code as shown below is not working with Jekyll versions >= 1.0. See this post how to update your Jekyll installation to version 1.0. Juan Antonio Navarro Pérez kindly put a fixed version of the code on GitHub.
After I messed around with Maruku for some time now, I became fed up with its limitations such as missing fenced code blocks. Without these, you have to use the unwieldy Liquid tags to denote a piece of code. Fortunuately, there are many alternative Markdown converters. To decide which one to use in the future, I came up with this (incomplete) feature matrix:
Feature | Maruku | Redcarpet | Kramdown | Pandoc |
---|---|---|---|---|
Fenced code blocks | – | ✓ | ✓ | ✓ |
Footnotes | ✓ | – | ✓ | ✓ |
Jekyll integration | ✓ | ✓ | ✓ | – |
Header IDs | ✓ | – | ✓ | ✓ |
Inline math | – | – | ✓ | ✓ |
Abbreviations | ✓ | – | ✓ | ✓ |
Pygments | ✓ | – | – | ✓ |
At first glance, Kramdown wins hands down (even ahead of my beloved Pandoc). But there is one slight problem: When blogging with Jekyll, you have to use CodeRay for syntax highlighting or none at all. Because I favor Pygments due to the broader range of supported languages, I had to update the Markdown converter plugin that I presented in the last post.
For this, we have to subclass Kramdown’s HTML converter to use Pygments on code blocks:
require 'kramdown'
require 'pygments'
require 'typogruby'
module Kramdown
module Converter
class Pygs < Html
def convert_codeblock(el, indent)
attr = el.attr.dup
lang = extract_code_language!(attr)
if lang
add_code_tags(
Pygments.highlight(el.value,
:lexer => lang,
:options => { :encoding => 'utf-8' })
)
else
"<pre><code>#{el.value}</code></pre>"
end
end
def add_code_tags(code)
code = code.sub(/<pre>/,'<pre><code>')
code = code.sub(/<\/pre>/,"</code></pre>")
end
end
end
end
Now, we can replace the Maruku converter with our customized Kramdown converter:
module Jekyll
class MarkdownConverter < Jekyll::Converter
def convert(content)
setup
html = Kramdown::Document.new(content, {
:auto_ids => @config['kramdown']['auto_ids'],
:footnote_nr => @config['kramdown']['footnote_nr'],
:entity_output => @config['kramdown']['entity_output'],
:toc_levels => @config['kramdown']['toc_levels'],
:smart_quotes => @config['kramdown']['smart_quotes']
}).to_pygs
return Typogruby.improve(html)
end
end
end
Note, that Kramdown uses weird dynamic name resolution (the method call
to_pygs
in this case) to hook the subclassed Pygs
class into the conversion
process. For my taste, this goes a bit too far but that’s the way it is.