コードブロックについてまとめて理解したい
CommonMark におけるコードブロックの仕様とコードブロックで出来ることをまとめてみたい。
■ 2 つのコードブロック
まず、一部の言葉に関して次のように定義しておきたい。
-
コードフェンス (code fence):
3 つ以上の連続するバックチック (
`
) やチルダ (~
) のこと。コードフェンスにはコードブロックを開始する フェンス開き と終了する フェンス閉じ がある。↓ フェンス開き ``` ここはコードブロック ``` ↑ フェンス閉じ
フェンス開きの行には情報文字列を与えることができ、コードブロックを含めることは出来ない。
フェンス閉じの
`
や~
の数は、フェンス開きの数と同じまたはそれよりも多い必要がある。 -
情報文字列 (info string):
コードブロック内に関する情報。プログラミング言語などを指定することが出来る。
↓ 情報文字列(ここでは `python`) ```python print("Hello World") ```
この情報文字列はフェンス開きのみに付与することが出来る。(フェンス閉じには与えられない)
コードブロックには Indented code block と Fenced code block がある。これらの特徴・違いについて表にした。
特徴・違い | Indented code block | Fenced code block |
---|---|---|
記法 | 行頭に半角スペース 4 つ | コードフェンスで囲う |
コードブロックの終了位置 | コードが書かれているところまで |
|
空白行を含める | 可 | 可 |
コードブロック末行の空白行 | 不可 | 可 |
コードブロック内のインデント | 行頭の半角スペース 4 つにインデントを続ける | フェンス開きのインデント位置を基準にインデント |
情報文字列の有無 (シンタックスハイライト等) |
無 | 有 |
パラグラフの中断 (interrupt) | 不可 | 可 |
フェンス開きのインデントは半角スペース 3 つまでが許容される。これは半角スペース 4 つのインデントで Indented code block として解釈されるためである。
コードフェンスでは、チルダ (~
) とバックチック (`
) があるが、これらは情報文字列に含ることのできる文字について違いがある。バックチックによるコードフェンスの情報文字列にはバックチックを含められないが、チルダによるコードフェンスの情報文字列にはチルダを含めることが出来る。Example 145, Example 146
```
バックチックで表現されたコードブロックの
情報文字列には “`” を含められない
```
~~~
チルダで表現されたコードブロックの
情報文字列には “~” と “`” を含められる
~~~
CommonMark の仕様についてはここまで。
■ 情報文字列によるコードブロックの拡張
情報文字列にはさまざまな情報を含めることが出来る。これによって、Fenced code block はシンタックスハイライト付きのコードブロックやダイアグラム、キャプションの付与などさまざまなことが出来るようになる。
情報文字列にはシンタックスハイライトを指定するプログラミング言語等に続いて、さまざまな情報が付与される。
ちなみに、CommonMark では情報文字列が Fenced code block のどこに書かれるかなどは決められているが、どのような文字列がどのような結果を生じさせるかは明記していない。そのため、ツールによってさまざまな拡張がなされている。類似したツールもあるため、似た結果を得るものであっても情報文字列や記法が異なる。
▽ シンタックスハイライト
Fenced code block の情報文字列にプログラミング言語名やそのエイリアスを含めることで、その言語のシンタックスハイライトを得ることが出来る。これらを得るには、次のようなシンタックスハイライトツールが利用される。
情報文字列における言語名やそのエイリアスの命名規則には統一性がない。そのため、ハイライトツールが異なるパーサに移植する場合、ハイライトが加えられないことがある。これは特にターミナルで実行するコマンドラインへのシンタックスハイライトで顕著である。
コマンドラインの実行と結果をハイライトしたい - Qiita
● 差分の表示
以下のようにすることで、単純なコードの表示だけでなく、コードの差分を表現することが出来る。
- 情報文字列:
diff
- コードの行頭に
+
や-
を置く- 追加される行を
+
- 削除される行を
-
- 追加される行を
```diff
- console.log("Goodbye")
+ console.log("Hello World")
```
- console.log("Goodbye")
+ console.log("Hello World")
また、diff
に続けて言語名やそのエイリアスを続けることで、言語シンタックスハイライトと共存させることも出来る場合もある。
Qiita では、_
でつなぐ。
```diff_javascript
- console.log("Goodbye")
+ console.log("Hello World")
```
- console.log("Goodbye")
+ console.log("Hello World")
Zenn では半角スペースでつなぐなど、diff
と言語名との間の文字が異なる。これにも統一性はない。
▽ キャプション
情報文字列で :
に続けてコードブロックのキャプションを付与することも出来る場合がある。
```javascript: JavaScript による Hello World
console.log("Hello World");
```
console.log("Hello World");
キャプションの内容はファイル名を示すことが多い。
▽ UML 等のダイアグラム
UML: Unified Modeling Language(統一モデリング言語)とは、システムの振る舞いや構造をダイアグラム(図)を用いて表現すること。
この UML に代表されるようなダイアグラムを Fenced code block から描くことが出来るツールがある。
例えば、Markdown Preview Enhanced (mume) で利用されるダイアグラムを作成するツールを列挙してみたい。⧉
この他にも、Erd、Bytefield、nomnoml、Svgbob、UMLet がある。
これらのツールを利用している場合、情報文字列を mermaid
や puml
などと指定することで、Fenced code block 内部のコードをダイアグラムに変換してくれる。Qiita では mermaid を利用することが出来る。
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
このようなダイアグラムのためのコードをコードブロックで表現したい場合、情報文字列を含めないようにすると良い。あるいは、# この節 にあるような追加制御のあるツールを利用すると良い。
シーケンス図やフローチャートなどを描くツールは数多くあるが、ベン図やサンキー・ダイアグラムを描くようなツールはないようだ。
▽ 数式
MathJax や KaTeX を利用できる場合、情報文字列を math
とすることで、ディスプレイ数式を表示させることが出来る場合がある。
```math
\left( \sum_{k=1}^n a_k b_k \right)^{\!\!2} \leq
\left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
```
\left( \sum_{k=1}^n a_k b_k \right)^{\!\!2} \leq
\left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
このような数式をコードブロックで表現したい場合は、情報文字列を latex
とすれば良いだろう。
▽ コードブロックへの追加制御
情報文字列には {
~}
で囲ってコードブロックへの追加情報を与えることが出来る場合がある。(Qiita ではこのような追加制御を与えることは出来ない)
例えば以下のような追加制御を加えることが出来る。
- コードブロックの行番号
- 開始番号の指定
- 特定行の強調
また、ダイアグラムを作成するようなツールを提供している場合、“ダイアグラムが生成されるコードブロックをそのまま表示する” ための追加制御を提供している場合もある。
▽ その他
この他にも、JSON による表の作成 (json:table
) や地図の表示(GeoJSON や TopoJSON)、STL 3D モデルを作成することも出来る場合がある。
JSON による表の作成 ⧉ は GitLab Markdown、地図の表示 ⧉ や STL 3D モデルの作成 ⧉ は GitHub Markdown で利用できる。
参考
- CommonMark Spec - 0.30
- Markdown 記法 チートシート - Qiita
- Diagrams - Markdown Preview Enhanced
- Creating diagrams - GitHub Docs
- GitLab Flavored Markdown (GLFM) - GitLab
- Kroki diagrams - GitLab
余談
コードブロックは Indented code block よりも Fenced code block の方が表記しやすく、さまざまな機能を得やすい。また、コードブロック内のインデントも書いていてわかりやすい。
Indented code block はパラグラフを中断しないため、書いていて難儀なことも多い。Fenced code blockで統一しておいた方が簡便だろう。
Fenced code block の情報文字列には、シンタックスハイライトを与えることがデファクトスタンダードのように扱われているが、言語やエイリアスの命名はツールによって異なる。書き手にとってはかなり面倒くさい。統一してほしい。本当に。
また、Fenced code block の情報文字列で遊びすぎでは????と思ってしまうほど、さまざまな機能が拡張されている。