HUGOのCode Block Render Hooksを使って、コードブロックにファイル名を表示する

Blog

Markdownのコードブロックに記述したコードを、「foo.js」のようにファイル名をつけて表示できるようにします。
スクリーンショット:ファイル名付きで表示したコードブロックの例

この記事では、v0.93.0で追加されたCode Block Render Hooksを使います。
Code Block Render Hooksが追加されるまでは、下記のページで紹介されているように、ショートコードを実装する必要がありました。
ソースコードをハイライト表示する (highlight)

Code Block Render Hooksを使うと、Markdown Syntaxのコードブロックのまま、ファイル名を表示できるようになります。
この場合、ショートコードを使うときとは異なり、JavaScriptのコードであればeslint-plugin-markdownを使ってESLintを適用できます。

動作を確認した環境

HUGO v0.93.0

Code Block Render Hooksとは

コードブロック用のRender Hooksは、layouts > _default > _markupの下に、render-codeblock.htmlを作成します。
参考. 公式ドキュメント

ファイルの位置
layouts
└── _default
    └── _markup
        └── render-codeblock.html
        └── render-codeblock-bash.html

表示する言語ごとに、Code Block Render Hooksテンプレートを出し分けることもできます。
render-codeblock-のプレフィックスと言語の識別子をファイルの名前につけます。
言語の識別子とは、````js` のようにバッククォート3つの後に付ける言語名のことです。

HUGOのドキュメントには、mermaid を使って図を表示する例が紹介されています。

ファイル名を表示するCode Block Render Hooksを実装する

コンテンツのファイルに、次のようにコードブロックを記述することを考えます。
表示するファイル名は、言語の識別子の後に{name="ファイル名"}のように記載します。

Markdownの例
```js {name="foo.js"}
(() => {
  'use strict';
  console.log("Hello World!");
})();
```

Code Block Render Hooksとして、render-codeblock.htmlに次の内容を記載します。

render-codeblock.html
<div>
  {{- $name := .Attributes.name -}}
  {{ with $name }}<div class="codeblock--name">{{ . }}</div>{{ end }}
  <div class="codeblock--content">
    {{- highlight (.Inner | safeHTML) .Type .Options }}
  </div>
</div>

{}内で渡したファイル名は、.Attributesで受け取ります。
コードブロック内の内容は.Innerで受け取ることができるため、highlight 関数でハイライト表示します。

HUGOでハイライト表示するときに{}内へ指定できる、行番号の開始数などのオプションは、.Optionsに格納されます。
highlight関数の第3引数として.Optionsを渡すと、同じように行番号の開始数などを指定できます。
行番号の開始数などのオプションの詳細は、Highlighting in Code Fencesを参照してください。

例えば、次のように行番号を変更したり、行をハイライト表示するオプションを指定してMarkdownを書いたとします。

Markdownの例
```js {linenos=table,hl_lines=["2-3"],linenostart=199,name="foo.js"}
(() => {
  'use strict';
  console.log("Hello");
})();
```

前述のrender-codeblock.htmlではhighlight 関数に .Options` を渡しているため、指定したオプションが反映されています。

スクリーンショット:行番号の開始や行のハイライトを指定したときの例

ちなみに、今回のファイル名の表示部分には、次のようなcssを適用しています。

.codeblock--name {
  width: fit-content;
  margin: 1rem 0 0;
  padding: 0.4rem;
  font-size: 0.9rem;
  color: rgb(255, 255, 255);
  background-color: #05acc1;
}

.codeblock--name + .codeblock--content {
  margin-top: 0;
}