MkDocs でスペース2個のインデントをリストのネストとして認識させたい場合
Markdown を HTML 化する手段として MkDocs は有用な選択肢だ。Sphinx の Markdown 版みたいな使い心地である。
しかし唯一残念なのが (リスト等をネストさせる時の)インデントがスペース4個強制 であること。これがスペース2個だと認識されない。
そこでスペース2個で認識させるにはどうしたらいいか調べてみた。
結論
Python-Markdown の Extension である Mdx Truly Sane Lists を取り入れる。
適用手順
まずはインストール。
$ pip install mdx_truly_sane_lists
インストールされてるか確認。
$ pip freeze | grep mdx mdx-truly-sane-lists==1.1.1
お使いの MkDocs プロジェクトに組み込む。具体的には mkdocs.yml に以下を記述。
site_name: 2space indentation test markdown_extensions: - mdx_truly_sane_lists: nested_indent: 2
nested_indent
の値を 2 にする。
詳しく
関連情報や背景などを雑多に取り上げておく。
MkDocs が持つ Markdown to HTML 変換の仕組み
Python-Markdown を使用して変換している。
つまり Markdown 変換の挙動を制御するためには、この Python-Markdown に与える設定値を変える必要があるのだけど、MkDocs ではこの変更を設定ファイル mkdocs.yml 経由で行えるようになっている。それが上記の markdown_extensions
の記述。
- 参考: Configuration - MkDocs にもあるように、
Python-Markdown の拡張機能については以下を参照。
mdx_truly_sane_lists はサードパーティー製の拡張機能にあたる。
mdx_truly_sane_lists のソースはどうなってんの?
mdx_truly_sane_lists/mdx_truly_sane_lists.py を見るといい。
20行目 あたりだろうか、
TrulySaneBlockProcessorMixin.truly_sane_tab_length = self.getConfigs()['nested_indent']
mkdocs.yml にて指定した nested_indent
の値を読み込み、Python-Markdown に与えているという感じ。(詳しく読んでないけどたぶん)Python-Markdown 側で「Extension クラスを継承してパーサーを与えたら変換の挙動をカスタムできるよ」みたいになっていて、そのお作法に従って書いている&インデント数の指定を(nested_indent として指定した)2にしている、のだと思う。
スペース2個インデントの是非
Python-Markdown では スペース4個が正義 だと捉えている。
markdown/index.md から引用しておくと、
The syntax rules clearly state that when a list item consists of multiple paragraphs, "each subsequent paragraph in a list item must be indented by either 4 spaces or one tab" (emphasis added). However, many implementations do not enforce this rule and allow less than 4 spaces of indentation. The implementers of Python-Markdown consider it a bug to not enforce this rule.
とある。Markdown の仕様としてはスペース4個 or タブ1個が正しいので、それ以外のインデントはバグですよ というスタンス。
ただ、それじゃ困る(既にスペース2個の Markdown 実装も流通している)というわけで、一応回避策が用意してある。
In the event that one would prefer different behavior, tab_length can be set to whatever length is desired. Be warned however, as this will affect indentation for all aspects of the syntax (including root level code blocks).
tab_length
というプロパティを使えばいい。もっというと、以下のような感じでレンダークラス markdown.Markdown を使う時に指定する。
md = markdown.Markdown( tab_length=2, ... )
ただし、ここを変更しちゃうと、リストに限らず(Markdown 文法中で登場する)インデントのスペース個数が全部変わってしまうので注意。