Jekyll の 0.12.0 でシンタックス ハイライトが便利になった

※ これは Jekyll アドベントカレンダー の 25 日目の記事です

このブログの生成にも利用している Jekyll が約 1 年ぶりにバージョン アップして 0.12.0 になった。RubyGems に公開されているので、gem update で更新できるはず。

この記事では、0.12.0 で個人的に注目している「シンタックス ハイライトに関する改善点」を 2 つ紹介する。

Jekyll の良さについては、俺の最強ブログ システムが火を噴くぜ で記事にしているので、知らない人はそちらからどうぞ。

Redcarpet 2 のサポート

まず 1 つ目は Redcarpet 2 のサポート。

Redcarpet は GitHub の中の人によって開発されている Markdown パーサーて、GitHub Flavored Markdown が使えるのが大きな特徴。

これまでも Jekyll では Redcarpet をサポートしていたが、Redcarpet 2 で外部 API が変わったので、Jekyll からは利用できない状態になっていた。

今回、Jekyll 0.12.0 で Redcarpet 2 の API に対応した。個人的には ``` での Fenced code blocks が使えるようになったのがうれしい。

たとえば、

```ruby
def fib(n);
    n <= 1 ? n : fib(n-1)+fib(n-2)
end
print fib(10)
```

と書くと

def fib(n);
    n <= 1 ? n : fib(n-1)+fib(n-2)
end
print fib(10)

となる。

これまでは「{% highlight ruby %}{% endhighlight %} で囲う」という面倒な書き方をしなきゃならなかった。どうしても ``` を使いたいときは Big Sky :: Jekyll で GitHub みたいな Triple Backtick を使う。 のように、独自にプラグインを作るハックもあるにはあった。

ちなみに、Redcarpet を利用するには、_config.yml に次のように書くのを忘れずに。

markdown:    redcarpet

シンタックス ハイライトの高速化

2 つ目は速度の話。

Jekyll はシンタックス ハイライトに pygments を使っている。Ruby で動く Jekyll から、Python で動く pygments を利用するには、何らかの工夫が必要になる。

Jekyll 0.11.2 までは Albino を使っていた。Albino はハイライトするたびに、Python のプロセスを実行して結果を取得していた。ハイライトするコード 1 つごとに Python が 1 プロセス立ち上がっていたので、当然、遅かった。

そこで、Jekyll 0.12.0 では pygments.rb が利用されるようになった。pygments.rb は高速化のための工夫がほどこされている。

pygments.rb には 0.2 系と 0.3 系があって、それぞれ別の高速化手法が使われていて面白い。

pygments.rb 0.2 は RubyPython で無理やり

0.2 では、rubypython という Ruby 上で Python インタプリターを動かすライブラリーを使っている。FFI で動的ライブラリーを読み込んでがんばっているようだ。

導入にはビルド環境が必要なので面倒だけど、劇的に高速化された。同一プロセス内で完結するので、プロセス起動のオーバーヘッドが 0 になる。

と、そこまではよかったのだけど、Ruby ごと落ちることがある。再現性はない。うまくいくこともあるし、落ちることもある。自分の環境が Windows だから不安定なのかと思いきや、Jekyll の Issue にも上がっている ので、RubyPython か FFI の問題なのだろう。

pygments.rb 0.3 は Python を使いまわす

0.2 の「Ruby 上で Python」作戦は不安定だったため、0.3 では純粋な Python を呼び出す方式に戻った。ただ、毎回呼び出すのではなく、プロセスを使いまわすようにした。

0.3 でハイライト処理を開始すると、Ruby と pygments を媒介する Python スクリプト mentos.py が立ち上がる。Ruby からは標準入出力を使って mentos.py に処理依頼をして、ハイライト結果を受け取る。複数回ハイライトを実行しても、同じプロセスを使いまわす。

純粋な Python が動くので、プロセスが死ぬような心配もない。0.2 のころに比べれば少しだけオーバーヘッドはある印象だが、Albino に比べれば十分速い。プロセス内に取り込むという暴挙に出て手に負えなくなったものが、ひとたび我に返って、実用に耐える速さと安定性を手に入れた。

ただし、最新の pygments 0.3.3 は Windows では動かない。/dev/null が見つからないなど、いろいろエラーになったので、動くようにして pull request を出しておいた。取り込まれるといいな。(追記) 取り込まれて 0.3.4 として公開された!!

まとめ

Jekyll 0.12.0 の個人的にうれしいところをざっと紹介した。その他の変更点は History.txt を見れば載っているので、気になる人はぜひ。