GitHub Pagesの各ページに最終更新日を入れようと思ったので、Emacsにそのための設定を追加してみた。

By | 2020年11月8日

はじめに

GitHub Pagesで構築しているWebサイト(panda大学習帳外伝)も運用開始からそれなりに時間が経過し、ページ数も増えてきたので、今後は最終更新日時を各ページの先頭の方に表示することにしました。

ところが、この機能をGitだけで実現しようとするとかなり敷居が高いことがわかってきました。そこで、Emacsにもご登場をいただきつつ、Gitに依存しない方法で実現する方向で試してみることにしました。

スポンサーリンク

サクサクと設定。

基本方針

Gitに依存せず、かつ編集対象がGitHub Pagesのページだけに限定されるということが最大限に利用できる方法ということで、以下のアプローチで実現を試みることにしました。

  1. markdownファイルのYAMLヘッダに最終更新日時を表示するためのkeyを追加する。
  2. 前項で設定したkeyに対応する値(最終更新日時)を挿入するための記述をmarkdownファイルの本文中に追加する。
  3. Emacsでmarkdownファイルを保存した時に前々項で設定したkeyに対応する最終更新日時を挿入するための関数を定義し、ファイル保存時のフックに追加する。

markdownファイル側のYAMLヘッダへのkeyの追加

YAMLヘッダの適当なところに、以下のように記述します。

update:

 
update:の後ろに表示させたい文字列をEmacsを使って挿入させようという魂胆です。

なお、GitHub Pages用のmarkdownファイルに必要な記述(YAMLヘッダを含む。)をテンプレート化し、そのテンプレートを挿入するEmacs lispの関数(↓)を定義して、.emacs/init.el等に書いておくといろいろと便利です。

;; Set template for GitHub Pages.
;; See https://pandanote.info/?p=6871 for details.
(defun markdown-insert-github-pages-template (page-title)
"Insert template for GitHub Pages."
(interactive "sTitle: ")
(let ()
(insert (concat
"---\n"
"title: " page-title " - panda大学習帳外伝\n"
"description: \n"
"mathjax: true\n"
"image: \n"
"twitter: \n"
" card: summary_large_image\n"
"encoding: UTF-8\n"
"update: \n"
"---\n"
"{% include pagelink.md %}\n"
"# " page-title "\n"
"{% if page.update %}最終更新日: {{ page.update }} {% endif %}\n"
"## はじめに\n"
"## \n"
"## まとめ\n\n"
"## リンク\n"
"{% include pagelink.md %}\n\n"
))
)
)

※実際には広告挿入用のコードをテンプレートに含んでいますが、それらについては省略しています。

markdownファイル本文への挿入

スポンサーリンク

markdownファイルの本文の最終更新日時を挿入したいところに、以下のように記述します。

{% if page.update %}最終更新日: {{ page.update }} {% endif %}

 
Webでの表示が「最終更新日時」ではなく「最終更新日」となっているのは気にしない方向でお願いいたします。🙇‍♂️

この設定は前項で示したEmacs lispの関数に含んでいます。

Emacsの関数の追加と設定

.emacs/init.el等に以下の関数を追加します。

;; See https://pandanote.info/?p=6871 for details.
(defun insert-timestamp-for-githubpages ()
"Insert time stamp into the line starting from \"update: \"."
(interactive)
(goto-char 0)
(if (re-search-forward "^update:.*$" nil t)
(replace-match (concat "update: " (current-time-string) " " (format-time-string "%z"))))
)
(defun insert-timestamp-for-githubpages-for-markdown ()
"Check the major mode to invoke insert-timestamp-for-githubpages."
(when (eq major-mode 'markdown-mode)
(insert-timestamp-for-githubpages))
)
(add-hook 'before-save-hook #'insert-timestamp-for-githubpages-for-markdown)

markdownファイルのsaveが実行されたときに先頭からsaveされるファイルの中身をチェックし、行頭に”update:”と書かれている行が現れた場合には、初めて現れた箇所に限り最終更新日時を”update:”の直後に追加する(すでに更新日時がセットされている場合にはそれを置き換える)ための関数です。

動作例

前節の設定ができたところで、動作を確認します。


スポンサーリンク

Emacsでmarkdownファイルを開き、下図の赤矢印(a)及び(b)の部分を追加します。

追加したら、Ctrl-X Ctrl-Sでmarkdownファイルを保存します。

すると、上図の赤矢印(a)の部分の表示が…

のように切り替わります。

このmarkdownファイルをcommit&pushしてしばらく待ち、このページにアクセスしてみると…

上図の赤矢印のように最終更新日時が挿入されたページが公開されていることが確認できました。👍

動作確認はこれにて完了です。

まとめ

ページの更新が完了したと思った時に最終更新日時を表示するコマンドを実行してその結果をコピペ… という作業をページの更新の都度行うよりは、既存の操作の一部に組み込まれる形で自動的にセットするような仕組みにできた方が少し長い目で見たときには手間を削減できそうだと思っていたので、実現できて助かりました。

おまけ: Gitのキーワード展開とタイムスタンプ

GitではSubversionやCVSにあったキーワード展開機能(ファイル中になどと書いておくと、commit時にその部分が日付などの文字列に置換される機能)が大幅に縮小されていて、commit時のSHA-1チェックサム以外のものをcommit時にキーワード展開の対象としたい場合には、リポジトリごとに以下の手順で設定を行う必要があります[1]。

  1. .gitattributesファイルにフィルタを使用する旨の設定(フィルタ名(プログラム名ではないことに注意。)を含む)を行う。
  2. checkout時に使用するプログラム(スクリプトでも可。以下同じ。)を書く。
  3. commit時に使用するプログラムを書く。
  4. 手順2及び3で書いたプログラムをgitコマンドで登録する。

なお、SHA-1チェックサムについてもローカルコピーのトップディレクトリにある.gitattributesファイルに必要な設定を行う必要があり、その設定を行った上でキーワード展開した後の文字列を挿入したいファイルの文字列を挿入する部分にと書くと展開できます。

書いたり読んだりするだけでもかなり手間のかかる作業になることが予想できます。

Linux上でリポジトリのファイルの編集を行っている場合には上記の設定を行う価値はあるかもしれませんが、Windows上でリポジトリのファイルの編集を行うという使い方のみが想定される場合には、上記の手順2及び3で書いたプログラムを確実に動かすための環境整備等に手間取ることが予想されたため、今回は採用を見送ることとしました。

この記事は以上です。

References / 参考文献

  1. 8.2 Customizing Git – Git Attributes