Skip to content

org-mode で書かれた howm メモを jekyll に出力する

2014/10/19

org-mode を使って howm でメモをとっているのですが、 メモの閲覧はブラウザでできたらいいなぁと思いつつも org-mode のデフォルトの html 出力はちょっとさびしいと思っていました。 そこで、いい機会なので何かと耳にする jekyll を試してみることにしました。

調べてみると org-mode と jekyll を利用している方々のページが見つかったので、 それらを参考にしました。

emacs の設定

メモファイルを jekyll で扱えるようにするため、 org-publish を使用して メモファイルすべてを jekyll 用の html ファイルに変換していきます。 また、その変換には ox-jekyll.el で定義されているバックエンドを使用する 予定だったのですが、自分のメモのフォーマットに合わせたり、 pygments を利用したかったこともあって、拡張したものを用意することになりました。 それが以下になります。

(require 'cl-lib)
(require 'ox)
(require 'ox-publish)
(require 'ox-jekyll)
(require 'uuid)

(defvar my-org-howm-jekyll--src-table nil)

(defun my-org-howm-jekyll--yaml-front-matter (info)
  (let* ((headline
          (assoc 'headline
                 (cddr (plist-get info :parse-tree))))
         ;; タイトルは最初のヘッドラインを使用
         (title (or (org-element-property :raw-value headline)
                    (org-jekyll--get-option info :title)))
         (date
          (org-jekyll--get-option info :date))
         (layout
          (org-jekyll--get-option info :jekyll-layout org-jekyll-layout))
         (categories
          (org-jekyll--get-option info :jekyll-categories org-jekyll-categories))
         (published
          (org-jekyll--get-option info :jekyll-published org-jekyll-published))
         (comments
          (org-jekyll--get-option info :jekyll-comments))
         ;; 最初のヘッドラインからタグを取得
         (tags
          (mapconcat 'identity (org-element-property :tags headline) " ")))
    (unless (equal published "true")
      (setq title (concat "[PREVIEW] " title)))
    (concat
     "---"
     "\ntitle: \""    title "\""
     ;; "\"\ndate: "     date
     "\nlayout: "     layout
     "\ncategories: " categories
     "\npublished: "  published
     "\ncomments: "   comments
     "\ntags: "       tags
     "\n---\n")))

(defun my-org-howm-jekyll-template (contents info)
  (if org-jekyll-include-yaml-front-matter
      (concat
       (my-org-howm-jekyll--yaml-front-matter info)
       contents)
    contents))

(defun my-org-howm-jekyll-escape (contents)
  (replace-regexp-in-string "\\([{}%]\\)" "{% raw %}\\1{% endraw %}" contents))

(defun my-org-howm-jekyll-src-block (src-block contents info)
  (if org-jekyll-use-src-plugin
      ;; エスケープ処理を避けるためにプレースホルダーとして uuid を使用
      (let ((id (uuid-string))
            (language (org-element-property :language src-block))
            (value (my-org-howm-jekyll-escape
                    (org-remove-indentation
                     (org-element-property :value src-block)))))
        (push (cons id
                    (format "{%% highlight %s %%}\n%s{%% endhighlight %%}"
                            language
                            value))
              my-org-howm-jekyll--src-table)
        id)
    (org-export-with-backend 'html src-block contents info)))

(defun my-org-howm-jekyll-final-function (contents backend info)
  (let ((escaped (my-org-howm-jekyll-escape contents)))
    (if org-jekyll-use-src-plugin
        ;; プレースホルダーの展開
        (cl-loop for (id . src) in my-org-howm-jekyll--src-table
                 do (setq escaped
                          (replace-regexp-in-string id
                                                    src
                                                    escaped
                                                    nil
                                                    t))
                 finally (progn
                           (setq my-org-howm-jekyll--src-table nil)
                           (cl-return escaped)))
      escaped)))

(org-export-define-derived-backend 'howm-jekyll 'jekyll
                                   :translate-alist
                                   '((src-block . my-org-howm-jekyll-src-block)
                                     (template . my-org-howm-jekyll-template))
                                   :filters-alist
                                   '((:filter-final-output . my-org-howm-jekyll-final-function)))

(defun my-org-howm-jekyll-publish-to-html (plist filename pub-dir)
  (org-publish-org-to 'howm-jekyll filename ".html" plist pub-dir))

タイトルやタグの取得方法を変更して、 html 全体から liquid のマークアップとして 解釈されそうな文字を一通りエスケープするようにしました。 ただ、 pygments を使うための highlight タグはそのままにする必要があったので、 変換中はプレースホルダーとして uuid 文字列を置いて、エスケープ処理後に 展開するようにしました。ちょっと無理やりな気もしますが、他にいい方法が 思いつきませんでした。

あとは、これを使って次のような形で org-publish 用の設定を追加しました。

(add-to-list 'org-publish-project-alist
             '(("howm"
                :base-directory       "path/to/memo"
                :publishing-directory "path/to/repo/_posts"
                :jekyll-categories    "howm"
                :base-extension       "howm"
                :recursive            t
                :publishing-function  my-org-howm-jekyll-publish-to-html
                :section-numbers      nil
                :with-toc             nil
                :with-tags            nil
                :with-sub-superscript nil)))

あとは必要に応じて M-x org-publish howm とするだけです。

jekyll

jekyll の方はあまり手の込んだことをするつもりはなかったので jekyll bootstrap を使って _config.yml に次の 2 行を追加して 必要ない部分はコメントアウトしました。

highlighter: pygments
lsi: true

また、関連記事取得用に gsl と rb-gsl をインストールしました。

おわりに

これでやっと howm のメモをブラウザで閲覧できるようになりました。 関連記事はいくらかランダムな感じもありますが、個人的には十分でした。 それと、 emacs の設定ファイルも org-mode で書いているので それらも jekyll を使って見れるようにしました。ただ、このままだと不便なので そのうち改善したいところです。

広告

From → Emacs

コメントする

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。