こんにちは、Markdown ソムリエです。
今気づいたけど Qiita って commonmark に準拠してないのかな。fenced code block が段落を interrupt してくれない。
— tk0miya (@tk0miya) February 8, 2020
Qiita でメモを書いているときに、ふとこんなことに気づきました。
段落の interrupt とは?
CommonMark spec を一通り読んでいるみなさんなら "〜〜〜 can interrupt a paragraph" という記述を何度も目にしたことがありますよね。この interrupt は、あるマークアップが段落に 割り込み、別の要素を開始できるかどうかを意味しています。
通常、CommonMark では空行を段落の終わりとみなすことになっています。
ここは段落1です。
ここは段落1の続きです。
まだ段落1です。
ここは段落2です。空行を入れると段落が終わります。
* 空行を挟んで箇条書きを書きます。
あらたな段落です。
テキストの状態でもテキストのかたまりが段落と認識できますし、自然な文法に感じられます。
ちなみにファイルの末尾も段落の終了と認識されます。
これに対し、「段落の interrupt」は 空行を含めずに 別の要素を書き始めることを許容する文法です。たとえば、次の例は段落と箇条書きの間に空行を入れていませんが、箇条書きの開始に合わせて段落が終了するものと解釈されます。
段落1です。
* 空行をはさまずに箇条書きを書いても、ここはリストとして認識されます。
そして、ツイートしたように、Qiita Markdown はこの段落の interrupt に対応していないようです。段落と箇条書き、段落とコードブロックといった要素の切り替わりの際は空行を入れる必要があります。他の処理系と同時に使っている人は解釈の差に気をつけてるとよいでしょう (GitHub とかね)。
ところで、CommonMark ではどう定義されているの?
CommonMark ではそれぞれのブロックレベルの要素ごとに段落に interrupt できるかどうかが定義されています。
記法 | interruptできる? |
---|---|
Thematic breaks | できない。Setext headings と解釈される。 |
ATX headings | できる |
Setext headings | できない。直前のテキストは段落ではなく、見出しと解釈される。 |
Indented code blocks | できない |
Fenced code blocks | できる |
HTML blocks | できる要素とできない要素がある (type7 の要素はできない)。 |
Link reference definitions | できない |
Paragraphs | できない |
Blank lines | できる |
Block quotes | できる |
Bullet lists | できる。ただし、中身が空の箇条書きはできない。 |
Ordered lists | できない。ただし、番号が 1 で、中身がある場合はできる |
おおよそ要素ごとに決まっているので、覚えるのは難しくありません。ルールが多いように見えますが、個人的には実際に書いてみると納得感があるものが多いので違和感はありません。ただ、意識をしないとマークアップをしたつもりが、段落の一部として解釈され、本文として表示されてしまうことがあるのでご注意ください。
ひとつだけ複雑で興味深いのは Ordered lists のルールです。1 からはじまる箇条書きの場合のみ interrupt できます。
段落です。
1. 1番から始まるこの箇条書きは割り込みできます。
段落です。
5. 他の番号から始まるこの箇条書きは割り込みできません (段落の続きと解釈されます)
とてもヒューリスティックなルールですよね。一貫性とは…と気が遠くなりますが、手に馴染む文法です。
ちなみに実装泣かせです。
まとめ
- CommonMark ではいくつかの記法が段落を interrupt できる
- ややこしい例外はあるが、書きやすいように調整されている印象 (私には)
- Qiita は段落の interrupt に対応していないため、改行を入れましょう
そのうち暇を見て、逆のパターンである「他の要素の直後に、段落を書いた場合の挙動」について説明しようと思います。