メインコンテンツへスキップ

Hugoのコードブロックのカスタム

·
ポートフォリオサイトをHugoで作成した - This article is part of a series.
Part 3: This Article

なにこれ
#

  • HugoのコードブロックにQiita記法でファイル名を表示できるようにした
  • コンテンツディレクトリの配下に該当ファイルが存在する場合にそこからコードを読み取るようにした
  • 行番号が表示されているコードブロックをコピーした時に行番号が含まれないようにした

Qiita記法でのファイル名の表示
#

QiitaやZennでは<language>:<file-name>の記法でファイル名を表示できます。
Hugoではlayouts/_default/_markup/render-codeblock.htmlを編集することでファイル名の表示に対応できます。 参考情報ではHugoの Syntax highlightingのオプションにファイル名の項目を追加するか、JavaScriptを使用してQiita記法に対応させていました。

しかし、shortcodeを使えばrender-codeblock.htmlのみで完結できました。
またついでに、取得したファイル名が配下にあれば直接読み込んで表示できるように対応しました。

言語タイプは.Typeで取得できるので:で分割して先頭と末尾を読み込んで同じ文字列でなければ、ファイル名を表示する感じです。

layouts/_default/_markup/render-codeblock.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<div>
  {{- $typeAndName := split .Type ":" -}}
  {{ $type := index (first 1 $typeAndName) 0 }}
  {{ $name := index (last 1 $typeAndName) 0 }}
  {{ with $name }}
    <div
      class="codeblock--name text-sm mt-1 py-1 px-1.5 rounded-t-lg"
      style="background-color: rgb(75 85 99); 	width: fit-content;"
    >
      {{ . }}
    </div>
  {{ end }}
  <div class="codeblock--content">
    {{ $absPath :=  path.Join (path.Dir .Page.File.Path) $name }}
    {{ if and (not (eq $type $name)) (fileExists $absPath) }}
      {{- highlight ($absPath | readFile | safeHTML) $type .Options }}
    {{ else }}
      {{- highlight (.Inner | safeHTML) $type .Options }}
    {{ end }}
  </div>
</div>

Blowfishではコードブロックの周りにパディングがありファイル名の領域との間に空白ができていました。 そのため、custom.cssでコードブロックの上側のパディングを除去しました。 影響範囲を小さくするため、子孫にlanguage-を含むクラス名を持つ場合にのみ作用させるようにしました。

aseets/css/custom.css
1
2
3
4
5
6
7
8
9
.chroma:has([class^="language-"]) {
  margin-top: 0;
  border-top-left-radius: 0;
}
.chroma .lntable:has([class^="language-"]) {
  margin-top: 0;
  border-top-left-radius: 0;
  overflow-x: auto;
}

コピー時に行番号を含めないようにする
#

Blowfishではコードプロック内にコピーボタンを表示させることに対応しています。 しかし、行番号の表示をした場合に行番号も一緒にコピーされていました。 そのため、行番号を削除するようにBlowfishのassets/js/code.jsをコピペしてcopyCodeClipboard()関数を改変しました。

行番号は[行番号][whitespace]の形式になっており桁揃えがされます。 そのため、正規表現は(\s*)+\d+\sになります。(\s*)は桁揃え用の0回以上の空白にマッチします。 また、置換後に残る先頭の改行を除去しています。

assets/js/code.js
1
2
3
4
5
6
7
...

async function copyCodeToClipboard(button, highlightDiv) {
  const _codeToCopy = highlightDiv.querySelector(":last-child").textContent
  // remove lines include only numbers and whitespace and replace empty lines
  const codeToCopy = _codeToCopy.replace(/^(\s*)+\d+\s/gm, "")
...

余談
#

Qiita記法に対応させたのはここで書いた記事を他に持っていくときにコピペで持っていきやすいためです。

ファイルから読み込む場合はprettierのコードフォーマットを適切に動作させるために次のようにダミーテキストを入れなければなりません . . .。

1
2
3
```python:main.py
dummy
```

参考
#

ポートフォリオサイトをHugoで作成した - This article is part of a series.
Part 3: This Article