[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

Magit でコメントの履歴を便利に使う (前編)

Magit についての小ネタを 2 つ紹介。今回が前編です。後編はこちら

WindowsVCS のフロントエンドとして Tortoise 某を使っていると、過去のコミット時に入力したコメントを再利用できるのが非常に便利だと感じるようになります。何度か続けて似たようなコメントを書くことが結構あるからです。Emacs の標準 VCS フロントエンドである vc.el や Magit でも、コメント入力ウィンドウで M-p / M-n を押すと、過去に入力したコメントを取り出すことができます。
ですが、その履歴は log-edit-comment-ring という変数に記録されているだけなので、 Emacs を終了すれば失われてしまいます。そこで、 session.el を使って履歴をずっと残すようにしてみましょう。

;;;
;;; log-edit.el のコメント履歴を session.el で保存する
;;;

;; session.el で保存するコメント履歴
(defvar my-log-edit-comment-ring nil)

;; コメント履歴が追加された時に `log-edit-comment-ring' を session.el で保存できる形式に変換
(defadvice magit-log-edit-push-to-comment-ring (after my-store-log-edit-commment-ring activate)
  (setq my-log-edit-comment-ring (my-ring-to-list log-edit-comment-ring)))

;; リングをリストに変換 (car にリングサイズ、cdr に要素)
(defun my-ring-to-list (ring)
  (when (ring-p ring)
    (append (list (ring-size ring)) (ring-elements ring))))

;; `my-ring-to-list' で作成したリストをリングに変換
(defun my-list-to-ring (l &optional newsize)
  (let* ((size (if newsize newsize (car l)))
         (orgelem (append (cdr l) nil)) ; 後でリストを破壊するので append を使ってリストをコピー
         (elem (reverse (if (>= size (length orgelem))
                            orgelem
                          (setcdr (nthcdr (1- size) orgelem) nil)
                          orgelem)))
         (ring (make-ring size)))
    (while elem
      (ring-insert ring (car elem))
      (setq elem (cdr elem)))
    ring))

;; session.el に保存したコメント履歴を log-edit.el に復元
(add-hook 'session-after-load-save-file-hook
          (lambda ()
            (when (boundp 'my-log-edit-comment-ring)
              (setq log-edit-comment-ring
                    (my-list-to-ring my-log-edit-comment-ring
                                     (when (boundp 'log-edit-comment-ring)
                                       (ring-size log-edit-comment-ring)))))))

勿論、別途 session.el を読み込んでいる必要があります。

動作確認環境は以下の通りです。

実装など細かい話

vc.el も Magit も、コメント履歴の管理を log-edit.el に委譲しています。変数 log-edit-comment-ring は、 ring.el によるリングバッファです。

元々 session.el は、 "-ring" で終わる名前の変数を自動的に記録してくれるのですが、 ring.el のリングバッファはリストの中にベクトルを含んでいるため、 session.el の管理対象から除外されてしまいます。そもそも session.el の管理から明示的に除外する変数を列挙する session-globals-exclude に vc-comment-ring (log-edit-comment-ring の昔の名前) がデフォルトで含まれていたりしますし、session.el と ring.el の相性は良くないのかもしれません。