summaryrefslogtreecommitdiff
path: root/posts/add-org-mode.md
blob: dd9a00d9b38a4333c6ab8478813f6e500605f7e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
title: org-mode で記事が書けるようになりました
id: add-org-mode
date: 2020-05-07 10:45
description: haunt を拡張して org-mode を使って記事を書けるようにした
---

## org-mode で記事を書きたい

今までの記事は全て `SXML` で直書きしていました。 しかし、ここ最近、 `org-mode` を本格的に使用するようになって、
いくらS式が好きだといってもさすがに `SXML` でブログを書くのは苦行であると気づきました。 今後 Guix
の紹介記事のような重要な記事を書く予定があるので、 `org-mode`
の強力なタスク管理を利用して記事を作成したいと考えています。

このブログは [Haunt](https://dthompson.us/projects/haunt.html) という、[GNU
Guile](https://www.gnu.org/software/guile/)
製の静的サイトジェネレータを使用して生成しているのですが、
サポートしている文書の形式は, `SXML`, `Texinfo`, `Skribe`, `CommonMark` の4つのみであったため、
デフォルトでは `org-mode` は使用できませんでした。

既に `org-mode` に依存してしまっているので、 `org-mode` で記事が書けないのは致命的です。 この問題を、 `Haunt`
を拡張することによって解決します。

## Haunt の紹介

[Haunt](https://dthompson.us/projects/haunt.html) は GNU Guile (Scheme
の処理系の一つ)で実装された静的サイトジェネレータで、 サイトの生成の仕方などを Guile で割と自由に拡張できるのが特徴的です。
このサイトでもブログ記事から対応する GitLab 上のソースコードにアクセスしたり、 記事の変更履歴を閲覧する機能が追加されています。
[ソースコードは公開されている](https://gitlab.com/tojoqk/www-tojo-tokyo)ので、興味のある方は確認してみてください。

Haunt の基本的な使い方については
[公式ドキュメント](https://dthompson.us/manuals/haunt/index.html)
を参照していただくことにして、 今回の説明に必要なところだけ解説します。 `haunt.scm`
というファイルでサイトをどのように生成するのかという設定を書き、
`posts` ディレクトリに記事を配置して `haunt build` というコマンドを実行すると良い感じにブログが生成されます。

`haunt.scm` で記事の `reader` を指定することができるので、 今回は `org-reader` という `org-mode`
用の `reader` を追加することで、 `org-mode` の記事を書けるように拡張します。

## org-reader の実装について

`commonmark-reader` の実装を確認したところ、 記事のファイルからメタデータと `SXML`
形式のコンテンツに変換できれば良いことが分かりました。

`Guile` だけで `org-mode` の文書を `SXML` に変換するのは骨が折れそうなので、
[Pandoc](https://pandoc.org/) を使用して `HTML` に変換して、それを `SXML`
に変換することで実現することにしました。

`Pandoc` を使用して `HTML` に変換する部分は
[org-string-\>html-string](https://gitlab.com/tojoqk/www-tojo-tokyo/-/blob/d85c05ec6ef778b38ade07cea05ed90b18bec606/www-tojo-tokyo/reader/org.scm#L31)
という手続きで実現しているのですが、 Guile でパイプの入出力を行なうプログラムを書くのが意外と難しかったです。 `(ice-9
popen)` が公式に提供している `open-pipe*` だと入力用のポートのみをクローズすることができないために、
エクスポートされていない手続きである `open-process` を使用しています。

``` scheme
(define (org-port->html-string port)
  (receive (read-port write-port pid)
      (open-process OPEN_BOTH "pandoc" "-f" "org")
    (put-string write-port (get-string-all port))
    (close-port write-port)
    (let ((result (get-string-all read-port)))
      (close-port read-port)
      (let ((status (cdr (waitpid pid))))
        (unless (zero? status)
          (error "pandoc return a non-zero status-code:" status)))
      result)))
```

非公開の手続きを使用しているので、正直微妙な気持ちになっていますが、 `shell` の代替として `Guile` が使えそうな雰囲気ですね。

`org-reader` 本体は下記のように実装しています。

``` scheme
(define org-reader
  (make-reader (make-file-extension-matcher "org")
               (lambda (file)
                 (call-with-input-file file
                   (lambda (port)
                     (let* ((metadata (read-metadata-headers port))
                            (html-string (org-string->html-string
                                          (get-string-all port))))
                       (values metadata
                               ((sxpath '(dummy *))
                                (xml->sxml
                                 (string-append "<dummy>"
                                                html-string
                                                "</dummy>"))))))))))
```

## まとめ

`org-mode` でブログを書けるようになりました。

Haunt は Hackable な静的サイトジェネレータで、Guile を使って簡単にカスタマイズできて結構楽しいです。
自分でブログを作成する予定のある人は一度検討してみてください。