kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

gitbook-plugin-regexplaceを利用して、ブロックレベル要素でMarkdownを囲む

GitBookは、色々な電子フォーマットで出力するドキュメントのためのツールです。

github.com

GitBookは紹介記事がたくさんあると思うので、説明は割愛しますが、このツール、主な記述言語としてMarkdownを採用しています。Markdown自体は色々な独自拡張がありますが、基本的にはプレーンなMarkdown+Github-Flavored-Markdownでサポートされている記法が使えるようです。

Markdownはシンプルな記法ですが、それだけでは表現力が不足することがあり、そういう場合、HTMLを書けということになっています。これで全て解決すればいいのですが、残念ながらそうはいきません。MarkdownにHTMLの断片を埋め込むのは簡単ですが、その逆はかなり厳しい制限がついています。

Daring Fireball: Markdown Syntax Documentation

に記述があるのですが、HTMLのブロックレベル要素内にはMarkdownを埋め込むことができないのです。この制限を緩和した、PHP Markdown Extraという拡張がありますが、これはGitBook内では使うことができません。

PHP Markdown Extra

この制限が問題になる場合はいくつかあるのですが、たとえば、

<div id="scala_code1" style="...">
 ```scala
 val foo = 1
 ```
</div>

のように、シンタックスハイライトされたコードをブロックレベル要素で囲み、それに対して特定のスタイルを適用したい、あるいはidを振りたいといった場合に困ることになります。

Markdownの処理過程に介入できない場合、基本的にはお手上げなのですが、幸いにもGitBookにはプラグイン機構があり、HTMLなどに変換する途中に別の処理を挟み込むことができます。

今回は、gitbook-plugin-regexplaceを使って問題を解決しました。このプラグイン、名前のごとく、Markdownの中で、特定の正規表現にマッチした文字列を別の文字列に置き換えるという機能を提供してくれます。

これを利用して、book.jsonに次のような記述を追加します:

{
  "plugins": [
    "regexplace"
  ],
  "pluginsConfig": {
    "regexplace": {
      "substitutes": [
        {"pattern": "<!-- begin div id=\"(.*)\" style=\"(.*)\" -->", "flags": "g", "substitute": "<div id=\"$1\" style=\"$2\">"},
        {"pattern": "<!-- end div -->", "flags": "g", "substitute": "</div>"}
      ]
    }
  }
}

その上で、本文に

<!-- begin div id="div1" style="display:none" -->
Markdown
<!-- end div -->

のように記述すると、HTMLに変換される際に、

<div id="div1" style="display:none">
Markdown
</div>

のように置き換えられるようになります。正直な話、正規表現による文字列マッチングで何でもかんでもやるのは好みではありませんが、木構造ベースの変換モデルを用意してくれていない(はず)以上、このような方法をとるしかないのでした。類似の機能を提供するプラグインとして、gitbook-plugin-sectionxというのがあるのですが、他のプラグインが使っているスタイルと衝突があったのかどうか、意図通りの結果が得られませんでした。