Hugo Academic でダーク・ライト両モードに対応した Chroma によるシンタックスハイライト

Background image by unsplash-logoMarkus Spiske

前提

Academic テーマ のデフォルト設定は ドキュメントにもある通り highlight.js を使ったもので、 この仕組みに乗っておけば基本的には問題ありません。

ただし highlight.js には一つ問題があって… EmacsLisp に対応していません (Lisp には対応)。 具体的には with-eval-after-load のような独自のマクロや、 DocString 中のクオテーションといった EmacsLisp 方言には対応出来ません。

一方、 Hugo 標準の Syntax HighlightingChroma を使ったもので、 こちらは EmacsLisp に対応しています

( ox-hugo の作者さんが過去に Issue に挙げてくれていた 模様…感謝 🙏)

CodePenChroma Playground とでそれぞれの出力結果を比べてみるとよく分かります:

(defvar hoge "fuga"
  "Doc String 中の `QUOTE' はどうなるかな?")

(with-eval-after-load 'foo
  (unless (eq t nil) "EmacsLisp 独自キーワードはどうなるかな?")
ソースコード 1: 元のコード
図1: highlight.js w/ GitHub style
図2: Chroma w/ GitHub style

そこで、 Academic を使いつつ、 Hugo 標準のハイライトの仕組みを使いたい というのが動機となります。

Academic 標準のコードハイライトを無効にする

ドキュメント に書かれている通り、 config.tomlparams.highlight オプションを無効にする必要があります。

Academic Kickstart をベースにしている場合、 params.toml で以下のように設定します:

# Enable source code highlighting? true/false
# Documentation: https://sourcethemes.com/academic/docs/writing-markdown-latex/#highlighting-options
highlight = false
ソースコード 2: params.toml

Hugo のコードハイライトを有効にする

Academic Kickstart をベースにしている場合、 config.toml で以下のように Hugo のコードハイライトが無効にされていると思います:

[markup.highlight]
  codeFences = false  # Disable Hugo's code highlighter as it conflicts with Academic's highligher.

これを以下のように変更します:

[markup.highlight]
  codeFences = true
  noClasses = false

noClasses = false としているのは、 ダーク・ライトの両方のモードに対応させるため です。 noClassestrue の場合、スタイル指定が HTML 中に埋め込まれます。 これだとモードの変更に追従して動的にスタイルを変更するということが出来ないため、 CSS クラスだけを HTML に埋め込んでもらうようにします。

ダークモード用とライトモード用の Chroma スタイルを決める

Chroma Style Gallery ギャラリーを参考に、 ダークモード時に使うスタイルとライトモード時に使うスタイルをそれぞれ決めます 。 モードの切り替わりに応じて、シンタックスハイライトのスタイル自体を変更してしまいます。

選定の際の注意事項として、 スタイルによって細かいクラス指定に対応していない場合があります

具体的には、 EmacsLisp の defvar などは NameBuiltin としてパースされ、 .nb というクラスが指定されるのですが、これが含まれていないスタイルがいくつかあります。

参考までに、調査した結果を以下に列挙します:

light スタイル

NameBuiltin が含まれるもの

NameBuiltin が含まれないもの

dark スタイル

NameBuiltin が含まれるもの

NameBuiltin が含まれないもの

Chroma 用の CSS を生成する

スタイルを決めたら以下のように CSS を生成します。 生成された CSS は標準出力に吐き出されるため、適当なファイルにリダイレクトするか、 pbcopy 等にパイプしてクリップボードに格納しましょう:

hugo gen chromastyles --style=pygments
hugo gen chromastyles --style=native

この後多少手を加える必要があるので、やりやすいように CSS 2 SASS/SCSS CONVERTER 等で SCSS に変換しておくとよいです。

Academic のテーマと競合しないようにする

生成した CSS(SCSS) は Academic のドキュメント に従い custom.css に追加します。

ただし、Academic には標準のハイライトのためのスタイル指定があるため、 Chroma が生成したスタイル指定をそのまま組込むと若干コンフリクトします。

そこで、多少手を加えてやります。

まずライトモード時のスタイルについては、 background-colorcolor が指定されていない場合があるため( pygments 等)、 Chroma Playground の出力結果を参考にしてスタイル指定を追加します。

また、 Academic 組込みの code へのスタイル指定より優先度が高くなるように、 セレクタを pre.chroma, .chroma code とします。

最終的に以下のようになります:

pre.chroma, .chroma code {

    background-color: #f5f5f5;
    color: #4a4a4a;

次にダークモード時のスタイルについては、 基本的に background-colorcolor も指定されていると思うので、 セレクタのみ .dark pre.chroma, .dark .chroma code としてあげます。

以上で、 Hugo Academic を使いつつ、 Chroma でシンタックスハイライト が実現出来ました。

yewton
ソフトウェアエンジニア

父親兼エンジニア

comments powered by Disqus

関連項目