Bloerg
         

Using Kramdown instead of Maruku

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.

Discussion

Martin
Tue, Jan 21 2014

Hi Matthias,

how do you know that redcarpet does not support pygments? I think I use pygments and redcarpet (see my blog and source)

Best regards, Martin

Matthias
Wed, Jan 22 2014

Hi Martin, you are partially right. You can use Redcarpet and Pygments within Jekyll, but Redcarpet by itself does not support Pygments out of the box. Moreover, as far as I remember, the Pygments support in Jekyll wasn’t working back at that time. Besides, there were other problems with Redcarpet as well, i.e. missing footnotes and header ids being the worst offenders.

This post might also have some comments at Google+.