Markdown/CommonMark 探訪(3):段落の割り込み

今日は Sphinx-users.jp の総会に行ってきました。
今年はとくになにも特別な活動をしない会長さんだったので、やや後ろめたい部分があったのですが、それもこれでおさらばです。
あたらしい会長の @usaturn 氏に頑張ってもらえれば、と思います。

さて、そんな感じで書き始めるのは第三夜でございます。
今日は小ネタで段落の割り込みについて紹介します。

CommonMark では記法ごとに段落に割り込むことができるかどうかが決まっています。
たとえば、themantic breaks は段落に割り込めます。

Foo
***
bar

これは foo, <hr />, bar と解釈されるわけですね。

一方でインデントされたコードブロック(Indented Code Blocks)は段落に割り込むことができません。

Foo
    bar

これは Foo bar というひとつの段落として扱われます。

このあたりは直感的のような、そうでないような、ちょっとむずかしいところですね。

それでは、この段落の割り込みまわりで、おや? とおもう例を紹介していきます。

HTML タグ

昨日も触れましたが、HTML はタグによって動作が変わります。
ブロック要素系のタグは段落に割り込むことができますが、インライン系のタグは割り込めません。

つまり

Foo
<div>
bar
</div>

はふたつのブロック (Foo という段落と <div> 以降の HTML ブロック) と解釈されますが、

Foo
<a href="bar">
baz

はひとつの段落にインライン HTML 要素があると解釈されます。

ここの解釈によって、強調やリンクなどのインライン要素の展開結果が異なるのですが、タグによって動作が違うというのは覚えづらいですね。Markdown マスターを目指す方は要注意です。

番号付きリスト

もうひとつは CommonMark のおかしなルールです。

The number of windows in my house is
14.  The number of doors is 6.

はひとつの段落として解釈されるのですが、なんと

The number of windows in my house is
1.  The number of doors is 6.

は 1行目は段落、2行目は番号付きリストとして解釈されます。

1番からはじまる番号付きリストは、段落に割り込むことができる要素なのです。
これが 2番から始まる場合は段落の割り込みが発生せず、段落が続いているものと解釈されます。

行の折り返しのあとに 1. や 1) からはじまる文章がある場合は注意が必要です。

themantic breaks の例外

Themantic breaks が段落の割り込みを発生させることは先ほど紹介しましたが、じつは特定の記号を使うと解釈結果が変化します。

Foo
---
bar

上記の例のように区切り文字に === や --- を使った場合、段落の割り込みは発生しないのですが、解釈結果が変化します。
前半のパートは段落ではなく、見出し (setext headings) として扱われます。
HTML で書くと <h2>Foo</h2><p>bar</p> となり、見出し(Foo)につづく本文(bar)とみなされます。

割り込みとは少しちがうのですが、 themantic breaks を間に入れようとしたときは、この点に注意が必要です。

訂正(12/10):=== は themantic breaks ではありません。--- だけでした。

おまけ:箇条書き

段落ではないですが、箇条書きでも割り込み的な例外処理があります。
それが themantic breaks の解釈です。

* Foo
* * *
* Bar

という記述があると、CommonMark パーサは箇条書き(Foo)、Themantic breaks (区切り線)、箇条書き(Bar) の 3つのパーツとみなします。

これが、別の箇条書き記号を使っていると解釈が変わります。

- Foo
- * *
- Bar

この場合、3項目のリストがあって、2番目の項目は空のリストを持っていると解釈します。

説明されると理解できるのですが、このリストの割り込みは微妙な挙動でした。
pycmark でも実装を進める中で、最後の方にこの問題が見つかって、がっかりしながら修正することになりました orz