Hugo + Org-Mode 執筆 Tips

tl;dr

ファイル archetypes/default.md に自分好みのテンプレを作ってボイラープレートを減らそう.最終的な org-mode 用の設定はこれ

https://raw.githubusercontent.com/ShigekiKarita/log/master/archetypes/default.org

はじめに

以前 Jekyll や org-mode でブログ書いてた時によく思ってたのが,タイトルとか日付といった「属性」を書くヘッダー的な部分をもっとテンプレ化しておきたいということ.移行した Hugo ではヘッダー的な部分を「Front Matter」と読んでいて,ユーザ定義もできたり無限に属性がある.

https://gohugo.io/content-management/front-matter/

Hugo といえば markdown で書いている人が多いと思うのですが,ファイル archetypes/default.md に自分好みのテンプレを作ってボイラープレートを減らせます.

$ hugo new posts/xxx.md

みたいなコマンドで新しい記事を生成するとき,そのテンプレ archetypes/default.md が選ばれて,その中のプレースホルダーが置き換えられるらしい.

課題

org-mode でのテンプレを作る方法がよくわからない.例えば markdown では archetypes/default.md をこんな感じで設定しています.

---
title: "{{ replace .Name "-" " " | title }}"
summary: ""
categories: ["uncategorized"]
tags: []
draft: true
date: {{ .Date }}
author: "Shigeki Karita"
isCJKLanguage: true
markup: "md"
---

## tl;dr

## reference

Front Matter の記法についてですが,ググると yaml/toml/json 色々でてきますが,おそらく yaml (--- で区切られる) がいまの標準っぽい.余談だが config.xxx は toml が標準なのでどれでも良いから統一して欲しい.

https://gohugo.io/content-management/front-matter/#front-matter-formats

解決

色々しらべた結果, org-mode は markdown のような区切り文字ではなく,こんな感じで archetypes/default.org に設定できる.

#+title: {{ replace .Name "-" " " | title }}
#+summary:
#+categories: uncategorized
#+tags:
#+draft: true
#+date: {{ .Date }}
#+author: Shigeki Karita
#+isCJKLanguage: true
#+markup: org

** tl;dr

** reference

どうやら org-mode 独自のヘッダーのようで,Front Matter 第四の記法というわけです.主な文法としては

  • 文字列を引用符でくくらない.引用符もそのまま出力されてしまう
  • tags のようなリスト値は `#+tags: foo bar** みたいな書き方

といった具合.文法はマニュアルを見てみたけど,いまいち細かいことはわからない. https://orgmode.org/manual/Property-Syntax.html#Property-Syntax

Hugo 側で独自に解釈しているところもあるっぽい.

こまかい話

具体的な書き方として, 一番役に立ったのはこの人のブログだ. とにかく沢山の記事がある.

この記事や手元の挙動を見ていると幾つか注意点として

  • markdown と違って org-mode の baseURL 的な解釈はうまくいってないようだ.
  • 例えばローカルの画像ファイルなどは記事ディレクトリを作り直下に置いて相対パスで指定するのがよい,その際に記事は index.org というファイル名に書く
  • そもそも mustache 的なテンプレートは効かない?
  • シンタックスハイライトは #+begin_src perl のような小文字ではダメで #+BEGIN_SRC perl としなければならない
# content/posts/foo/index.org という org ファイルを作ると
# {{ baseURL }}/posts/foo/index.html として生成される

# 大文字じゃないとダメ
#+BEGIN_SRC d
void main() {}
#+END_SRC

# 画像 content/posts/foo/bar.png というファイル
[[file:./bar.png]]

余談: D言語で実行時リフレクション

mustacheテンプレートエンジンといえば,Front Matterなんかは .Name とか明らかに Go っぽいフィールドにアクセスしていて,どうやってるのかなと色々調べたら, Go 言語にはリフレクションの公式パッケージがあるようだ.これは結構 Web 系のフレームワーク作りやすい気がする.

https://golang.org/pkg/reflect/#Value.FieldByName

エラー処理など真面目に作ると大変そうだが (Goでも既に大変そう),D言語にもコンパイル時リフレクションがあるので実行時の文字列で与えられるフィールドにアクセスすることはできる.ちょっと書いてみた.

import std.stdio;
import std.variant;

struct Hoge {
	int N;
    string S;
}

auto maxFieldSize(T)() {
    ulong size = 0;
    foreach (m; T.init.tupleof) {
        if (size < m.sizeof) size = m.sizeof;
    }
    return size;
}

auto fieldByName(T)(ref T x, string attr) {
    VariantN!(maxFieldSize!T) v;
    foreach (a; __traits(allMembers, T)){ 
        if (a == attr) {
            v = __traits(getMember, x, a);
            break;
        }
    }
    return v;
}

void main(string[] args) {
    const Hoge h = {10, "aa"};

    auto v = h.tupleof[0];
    auto name = __traits(allMembers, Hoge)[0];

    assert(h.fieldByName(name) == v);
    assert(h.fieldByName("N") == 10);
    assert(h.fieldByName("S") == "aa");
    // 元の Go のコード https://kwmt27.net/index.php/2013/10/02/get-field-value-of-struct-with-reflect-golang/
    // v := reflect.ValueOf(h) //Value
    // t := v.Type()           //Type
    // name := t.Field(0).Name
    // fmt.Println(name) //フィールド:N
    // fmt.Println(v.FieldByName(name).Interface()) //h.Nの値
}

やはりD言語の __traits 関係は何でも出来て最高.返り値を std.variant.VariantN で型消去してます. https://dlang.org/phobos/std_variant.html

そうえいばD言語でもちゃんとしたテンプレートエンジンがある,DでHugoみたいなやつ作ってみようかな? https://qiita.com/repeatedly/items/300041d55fd5b45b69e1

あとさっき twitter でD言語で実行時リフレクションライブラリがでてきたという話をみた. http://code.dlang.org/packages/hunt-reflection

最後に

org-mode のサポートは未だ experimental な機能っぽいので(ドキュメントにもあまりでてこない),不完全な部分もある.たとえばこの記事は markdown で書いているので PAGE CONTENT という目次がページ上部にちゃんとでていると思うが, org-mode で書いた記事には目次がでてこない.この辺はテーマのせいかもしれないし,切り分けが面倒なので今後の課題にしよう.次からは org-mode で記事を書こうと思う.私は markdown と org-mode どちらも良いものだと思っているので,両方使えるのは本当に良い.

それにしてもGo言語にはorg-modeのパーサー実装 (https://github.com/chaseadamsio/goorgeous) があるなんて,すごいコミュニティだと思った.やはりRuss Coxを始めパーサーやコンパイラ界隈の人々が多い気がする.