ランディネットワークの BLOG

Hugo で作ったサイトに Syntax highlighter を導入してみた

Created at:
Category: Hugo

ブログの記事などでプログラムのソースコードを貼り付けると、 色付けされた見やすい表示に変換してくれる Syntax highlighter (シンタックスハイライター)を導入してみました。

私が使っているバージョンの Hugo にも Syntax highlighter は入っているのですが、 HTML を生成するタイプのようです。 私はどちらかというと JavaScript で動作するものを使うほうが好みです。 生成された HTML に余分なタグが入ってほしくないからです。

なので、今回は highlight.js を組み込みむことにしました。

この highlight.js は 185 の言語に対応し、 90 のスタイルが準備されています。 マイナー(?) な Elixir や Groovy, Dockerfile にも対応しているので、色々と使えそうです。

また、行番号の出力に対応しない という考え方に共感しました。 私も 27年以上、テキストエディタに行番号を表示していません :-P

ダウンロード

まずは、 ダウンロードページ で Custom Package を作成します。 利用する言語を全て選択し、 Download ボタンをクリックすると zip ファイルがダウンロードされます。

このときに、全ての言語を取り込むとファイルが大きくなってしまうので、実際に使うものだけにしておきます。

あとから言語を追加したい場合

とはいえ、あとから言語を追加したくなることなんかは容易に想像つきます。 そんなときは、個別に取り込むことも出来るようです。 例えば、 以下のように script タグで languages/awk.min.js ファイルを読み込ませることで awk のソースでも Syntax highlighting がおこなわれるようになります。

<script
  charset="UTF-8"
  src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/languages/awk.min.js"></script>

まあ、こんな事するぐらいならダウンロードページで作り直すか、 初めから Node.js などで作るようにしておいたほうが良さそうです。 Github の highlight.js の README.md を見ると色々な組み込み方法が載っているので、そちらを参考にして下さい。

インストール

さて話を元に戻します。

さきほどダウンロードしたファイルを Hugo サイトデータの static ディレクトリ展開します。 以下のようにあらかじめ展開するディレクトリを作成してから、 unzip してください。

cd static
mkdir highlight
cd highlight
unzip ~/Download/highlight.zip

これで、 static/highlight/ ディレクトリにファイルが展開されました。 highlight.pack.js ファイルが 出来ているはずなので、以下のタグをテンプレートに記述して (テンプレートはテーマによります。無難な場所は <head> タグの中) Web ブラウザを再読み込みして下さい。

<link rel="stylesheet" href="/highlight/styles/default.css">
<script src="/highlight/highlight.pack.js"></script>
<script>
hljs.initHighlightingOnLoad();
</script>

以上で準備完了です。デフォルトのスタイルとプログラムを組み込んだ状態です。

あとは、ブログなどの記事に Markdown で記述して下さい。

``` awk
{
    print $1, $2;
}
```

上記の様に ``` 文字でソースコードの上下を囲むと色付けされます。

{
    print $1, $2;
}

スタイルシートの選択

デフォルトのスタイルでも良いのですが、他のスタイルを選ぶことも出来ます。 私は、 atom-one-dark.css を選びました。

先程の default.css の読み込み行を以下のように置き換えます。

<link rel="stylesheet" href="/highlight/styles/atom-one-dark.css">

zip ファイルを展開したディレクトリの styles ディレクトリにスタイルファイルがありますので、 色々試して探してみるのもいいと思います。

tree コマンドの出力を highlight.js で色付け

せっかくなので、ディレクトリツリーを端末に表示するツール tree の出力をフォーマット出来るようにしてみました。

例えば、以下のコマンドを実行したときに表示された結果を、

tree -F content/

Blog 記事の中で以下のように Markdown 記法で書いておくと、

``` tree
content/
├── _index.md
└── blog/
    ├── _index.md
    ├── images/
    │   └── hogehoge.jpg
    ├── post01/
    │   ├── images/
    │   │   ├── post01-head.jpg
    │   │   └── fugafuga.jpg
    │   └── index.md
    └── post02/
        ├── images/
        │   └── post02-head.jpg
        └── index.md
```

以下のように色付けされるというものです。

content/
├── _index.md
└── blog/
    ├── _index.md
    ├── images/
    │   └── hogehoge.jpg
    ├── post01/
    │   ├── images/
    │   │   ├── post01-head.jpg
    │   │   └── fugafuga.jpg
    │   └── index.md
    └── post02/
        ├── images/
        │   └── post02-head.jpg
        └── index.md

といってもトップのディレクトリと、 / で終わる部分を string クラスとしてスタイルを適用して、 バイナリファイル(.jpg, .png, .gif, .tiff, .mp4, .mp3) を number クラスとしてスタイルを適用する だけの単純な仕組みです。あとファイル名のマッチングルールも適当です。 使ってて他に欲が出たら直しながら使う感じで考えています。

tree 表示するための言語定義ファイルは以下のような感じになります。

hljs.registerLanguage('tree', () => {
  return {
    case_insensitive: true,
    contains: [
      {
        className: 'string',
        begin: '^[A-Za-z0-9 \_\-]+$',
      },
      {
        className: 'string',
        begin: '[A-Za-z0-9 \_\-]+/$',
      },
      {
        className: 'number',
        begin: '[A-Za-z0-9 \_\-]+\.(jpg|png|gif|tiff|mp4|mp3)$',
      }
    ]
  };
});

これを static/js/tree_highlight.js とか適当な名前で保存して以下のように組み込んで下さい。

<script src="/highlight/highlight.pack.js"></script>
<script src="/js/tree_highlight.js"></script>
<script>
hljs.initHighlightingOnLoad();
</script>

最初のところで書いていた awk の言語定義をあとから追加するなら、以下の場所に書くのが良いと思います。

<script src="/highlight/highlight.pack.js"></script>
<script src="/js/tree_highlight.js"></script>
<script charset="UTF-8"
  src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.9/languages/awk.min.js"></script>
<script>
hljs.initHighlightingOnLoad();
</script>

思ったよりも簡単に導入できて、新しい言語も簡単に定義できそうなので、しばらくはこの highlight.js を利用してみたいと思います。