コードブロックについてまとめて理解したい

# コードブロックについてまとめて理解したい

CommonMark におけるコードブロックの仕様とコードブロックで出来ることをまとめてみたい。

## ■ 2 つのコードブロック

まず、一部の言葉に関して次のように定義しておきたい。

- **コードフェンス (code fence)**:

    3 つ以上の連続するバックチック (`` ` ``) やチルダ (`~`) のこと。コードフェンスにはコードブロックを開始する **フェンス開き** と終了する **フェンス閉じ** がある。
    ````markdown
     ↓ フェンス開き
    ```
    ここはコードブロック
    ```
     ↑ フェンス閉じ
    ````
    フェンス開きの行には情報文字列を与えることができ、コードブロックを含めることは出来ない。

    フェンス閉じの `` ` `` や `~` の数は、フェンス開きの数と同じまたはそれよりも多い必要がある。

- **情報文字列 (info string)**:

    コードブロック内に関する情報。プログラミング言語などを指定することが出来る。
    ````markdown
        ↓ 情報文字列（ここでは `python`）
    ```python
    print("Hello World")
    ```
    ````
    この情報文字列はフェンス開きのみに付与することが出来る。（フェンス閉じには与えられない）

コードブロックには *Indented code block* と *Fenced code block* がある。これらの特徴・違いについて表にした。

|                      特徴・違い                       |             Indented code block             |                 Fenced code block                 |
| :---------------------------------------------------: | :-----------------------------------------: | :-----------------------------------------------: |
|                       **記法**                        |           行頭に半角スペース 4 つ           |               コードフェンスで囲う                |
|             **コードブロックの終了位置**              |       コードが書かれているところまで        | <ul><li>フェンス閉じ</li><li>最終行まで</li></ul> |
|                  **空白行を含める**                   |                     可                      |                        可                         |
|            **コードブロック末行の空白行**             |                    不可                     |                        可                         |
|           **コードブロック内のインデント**            | 行頭の半角スペース 4 つにインデントを続ける |  フェンス開きのインデント位置を基準にインデント   |
| **情報文字列の有無 <br>（シンタックスハイライト等）** |                     無                      |                        有                         |
|           **パラグラフの中断 (interrupt)**            |                    不可                     |                        可                         |

フェンス開きのインデントは半角スペース 3 つまでが許容される。これは半角スペース 4 つのインデントで Indented code block として解釈されるためである。

[commonmark-ex145]: https://spec.commonmark.org/0.30/#example-145 "CommonMark \- Example 145"
[commonmark-ex146]: https://spec.commonmark.org/0.30/#example-146 "CommonMark \- Example 146"

コードフェンスでは、チルダ (`~`) とバックチック (`` ` ``) があるが、これらは情報文字列に含ることのできる文字について違いがある。バックチックによるコードフェンスの情報文字列にはバックチックを含められないが、チルダによるコードフェンスの情報文字列にはチルダを含めることが出来る。<sup>[Example 145][commonmark-ex145], [Example 146][commonmark-ex146]</sup>

````markdown
```
バックチックで表現されたコードブロックの
情報文字列には “`” を含められない
```

~~~
チルダで表現されたコードブロックの
情報文字列には “~” と “`” を含められる
~~~
````

CommonMark の仕様についてはここまで。

## ■ 情報文字列によるコードブロックの拡張

情報文字列にはさまざまな情報を含めることが出来る。これによって、Fenced code block はシンタックスハイライト付きのコードブロックやダイアグラム、キャプションの付与などさまざまなことが出来るようになる。

情報文字列にはシンタックスハイライトを指定するプログラミング言語等に続いて、さまざまな情報が付与される。

ちなみに、CommonMark では情報文字列が Fenced code block のどこに書かれるかなどは決められているが、どのような文字列がどのような結果を生じさせるかは明記していない。そのため、ツールによってさまざまな拡張がなされている。類似したツールもあるため、似た結果を得るものであっても情報文字列や記法が異なる。

### ▽ シンタックスハイライト

Fenced code block の情報文字列にプログラミング言語名やそのエイリアスを含めることで、その言語のシンタックスハイライトを得ることが出来る。これらを得るには、次のようなシンタックスハイライトツールが利用される。

- [highlight\.js][github-highlight]
- [Prism\.js][github-prism]
- [Rouge][github-rouge]
- [Linguist][github-linguist]

[github-highlight]: https://github.com/highlightjs/highlight.js "JavaScript syntax highlighter with language auto-detection and zero dependencies. \- GitHub"
[github-prism]: https://github.com/PrismJS/prism/ "Lightweight, robust, elegant syntax highlighting. \- GitHub"
[github-rouge]: https://github.com/rouge-ruby/rouge "A pure Ruby code highlighter that is compatible with Pygments \- GitHub"
[github-linguist]: https://github.com/github/linguist "Language Savant. If your repository's language is being reported incorrectly, send us a pull request! \- GitHub"

情報文字列における言語名やそのエイリアスの命名規則には統一性がない。そのため、ハイライトツールが異なるパーサに移植する場合、ハイライトが加えられないことがある。これは特にターミナルで実行するコマンドラインへのシンタックスハイライトで顕著である。

[コマンドラインの実行と結果をハイライトしたい \- Qiita](https://qiita.com/Yarakashi_Kikohshi/items/e740d9a24f11caa76585)

#### ● 差分の表示

以下のようにすることで、単純なコードの表示だけでなく、コードの差分を表現することが出来る。

- 情報文字列：`diff`
- コードの行頭に `+` や `-` を置く
    - 追加される行を `+`
    - 削除される行を `-`

````markdown
```diff
- console.log("Goodbye")
+ console.log("Hello World")
```
````

```diff
- console.log("Goodbye")
+ console.log("Hello World")
```

また、`diff` に続けて言語名やそのエイリアスを続けることで、言語シンタックスハイライトと共存させることも出来る場合もある。

Qiita では、`_` でつなぐ。

````markdown
```diff_javascript
- console.log("Goodbye")
+ console.log("Hello World")
```
````

```diff_javascript
- console.log("Goodbye")
+ console.log("Hello World")
```

Zenn では半角スペースでつなぐなど、`diff` と言語名との間の文字が異なる。これにも統一性はない。

### ▽ キャプション

情報文字列で `:` に続けてコードブロックのキャプションを付与することも出来る場合がある。

````markdown
```javascript: JavaScript による Hello World
console.log("Hello World");
```
````

```javascript: JavaScript による Hello World
console.log("Hello World");
```

キャプションの内容はファイル名を示すことが多い。

### ▽ UML 等のダイアグラム

UML: Unified Modeling Language（統一モデリング言語）とは、システムの振る舞いや構造をダイアグラム（図）を用いて表現すること。

この UML に代表されるようなダイアグラムを Fenced code block から描くことが出来るツールがある。

例えば、Markdown Preview Enhanced ([mume][github-mume]) で利用されるダイアグラムを作成するツールを列挙してみたい。<sup>[⧉][mpe-diagram]</sup>

[github-mume]: https://github.com/shd101wyy/mume "Powerful markdown tool \- GitHub"
[mpe-diagram]: https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams "Diagram \- Markdown Preview Enhanced"

- [Ditaa][github-ditaa]
- [flowchart\.js][github-flowchart]
- [JS Sequence Diagrams][github-jssequence]
- [mermaid\.js][github-mermaid]
- [PlantUML][github-plantuml]
- [Vega][github-vega]
- [Vega-lite][github-vegaLite]
- [Viz][github-viz]
- [WaveDrom][github-waveDrom]

[github-ditaa]: https://github.com/stathissideris/ditaa "ditaa is a small command-line utility that can convert diagrams drawn using ascii art ('drawings' that contain characters that resemble lines like | / \- ), into proper bitmap graphics. \- GitHub"
[github-flowchart]: https://github.com/adrai/flowchart.js/ "Draws simple SVG flow chart diagrams from textual representation of the diagram \- GitHub"
[github-jssequence]: https://github.com/bramp/js-sequence-diagrams "Draws simple SVG sequence diagrams from textual representation of the diagram \- GitHub"
[github-mermaid]: https://github.com/mermaid-js/mermaid "Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown \- GitHub"
[github-plantuml]: https://github.com/plantuml/plantuml "Generate diagrams from textual description \- GitHub"
[github-vega]: https://github.com/vega/vega "A visualization grammar. \- GitHub"
[github-vegaLite]: https://github.com/vega/vega-lite "A concise grammar of interactive graphics, built on Vega. \- GitHub"
[github-viz]: https://github.com/mdaines/viz.js/ "A hack to put Graphviz on the web. \- GitHub"
[github-waveDrom]: https://github.com/wavedrom/wavedrom "🌊 Digital timing diagram rendering engine \- GitHub"

この他にも、[Erd][github-erd]、[Bytefield][github-bytefield]、[nomnoml][github-nomnoml]、[Svgbob][github-svgbob]、[UMLet][github-umlet] がある。

[github-bytefield]: https://github.com/Deep-Symmetry/bytefield-svg "Node module that generates byte field diagrams in SVG format \- GitHub"
[github-erd]: https://github.com/BurntSushi/erd "Translates a plain text description of a relational database schema to a graphical entity-relationship diagram. \- GitHub"
[github-nomnoml]: https://github.com/skanaar/nomnoml "The sassy UML diagram renderer \- GitHub"
[github-svgbob]: https://github.com/ivanceras/svgbob "Convert your ascii diagram scribbles into happy little SVG \- GitHub"
[github-umlet]: https://github.com/umlet/umlet "Free UML Tool for Fast UML Diagrams \- GitHub"

これらのツールを利用している場合、情報文字列を `mermaid` や `puml` などと指定することで、Fenced code block 内部のコードをダイアグラムに変換してくれる。Qiita では mermaid を利用することが出来る。

````markdown
```mermaid
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```
````

```mermaid
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```

このようなダイアグラムのためのコードをコードブロックで表現したい場合、情報文字列を含めないようにすると良い。あるいは、[\# この節][sec-addCtrl] にあるような追加制御のあるツールを利用すると良い。

[sec-addCtrl]: #-コードブロックへの追加制御 "# コードブロックへの追加制御"

シーケンス図やフローチャートなどを描くツールは数多くあるが、ベン図やサンキー・ダイアグラムを描くようなツールはないようだ。

### ▽ 数式

MathJax や KaTeX を利用できる場合、情報文字列を `math` とすることで、ディスプレイ数式を表示させることが出来る場合がある。

````markdown
```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)
```
````

```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)
```

このような数式をコードブロックで表現したい場合は、情報文字列を `latex` とすれば良いだろう。

### ▽ コードブロックへの追加制御

情報文字列には `{`\~`}` で囲ってコードブロックへの追加情報を与えることが出来る場合がある。（Qiita ではこのような追加制御を与えることは出来ない）

例えば以下のような追加制御を加えることが出来る。

- コードブロックの行番号
    - 開始番号の指定
- 特定行の強調

また、ダイアグラムを作成するようなツールを提供している場合、“ダイアグラムが生成されるコードブロックをそのまま表示する” ための追加制御を提供している場合もある。

### ▽ その他

この他にも、JSON による表の作成 (`json:table`) や地図の表示（GeoJSON や TopoJSON）、STL 3D モデルを作成することも出来る場合がある。

JSON による表の作成 <sup>[⧉][gitlab-jsonTable]</sup> は GitLab Markdown、地図の表示 <sup>[⧉][github-geojson]</sup> や STL 3D モデルの作成 <sup>[⧉][github-stl3d]</sup> は GitHub Markdown で利用できる。

[gitlab-jsonTable]: https://docs.gitlab.com/ee/user/markdown.html#json "JSON \- GitLab"
[github-geojson]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-geojson-and-topojson-maps "Creating GeoJSON and TopoJSON maps \- GitHub"
[github-stl3d]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-stl-3d-models "Creating STL 3D models \- GitHub"

# 参考

- [CommonMark Spec \- 0.30](https://spec.commonmark.org/0.30/)
    - [4.4 Indented code blocks](https://spec.commonmark.org/0.30/#indented-code-blocks)
    - [4.5 Fenced code blocks](https://spec.commonmark.org/0.30/#fenced-code-blocks)
- [Markdown 記法 チートシート \- Qiita](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
- [Diagrams \- Markdown Preview Enhanced](https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams)
- [Creating diagrams \- GitHub Docs](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams)
- [GitLab Flavored Markdown (GLFM) \- GitLab](https://docs.gitlab.com/ee/user/markdown.html)
- [Kroki diagrams \- GitLab](https://docs.gitlab.com/ee/administration/integration/kroki.html)

# 余談

コードブロックは Indented code block よりも Fenced code block の方が表記しやすく、さまざまな機能を得やすい。また、コードブロック内のインデントも書いていてわかりやすい。

Indented code block はパラグラフを中断しないため、書いていて難儀なことも多い。Fenced code blockで統一しておいた方が簡便だろう。

Fenced code block の情報文字列には、シンタックスハイライトを与えることがデファクトスタンダードのように扱われているが、言語やエイリアスの命名はツールによって異なる。書き手にとってはかなり面倒くさい。統一してほしい。本当に。

また、Fenced code block の情報文字列で遊びすぎでは？？？？と思ってしまうほど、さまざまな機能が拡張されている。