auto-view-mode

elispを書く時、emacsにバンドルされているel関数を参考にしたりするのですが、マイナーモードのview-modeを有効にすると便利だったりします。なので以下のようなフックをemacs-lisp-modeに設定しています。バンドルされたelファイルの判定は、特定のディレクトリ配下にあるかどうかで行います。

(add-hook 'emacs-lisp-mode-hook
          #'(lambda ()
              (and (string-match "/Applications/MacPorts/Emacs.app/Contents/Resources/lisp"
                                 (buffer-file-name))
                   (and (eq (match-beginning 0) 0)
                        (view-mode)))))

これを他のメジャーモードでも使いたかったので、ユーティリティを書きました。まずはメジャーモードのシンボルと、ディレクトリをマップしたalistを定義。

(defvar auto-view-mode-alist nil
  "Alist of elements (MAJOR-MODE . DIRECTORIES) to use for enabling View mode
when a buffer's mode is MAJOR-MODE and children of the DIRECTORIES.")

alistのkeyとなる各モードにフックする関数は、上記のものと似ています。

(defun view-mode-with-auto-view-mode-alist ()
  (let ((dirs (cdr (assoc major-mode auto-view-mode-alist))))
    (and (string-match (if (consp dirs)
                           (setq dirs (regexp-opt dirs))
                         dirs)
                       (buffer-file-name))
         (and (eq (match-beginning 0) 0)
              (view-mode)))))

そしてalistに要素を追加してフックを有効にしたりするユーティリティ群です。

(defun auto-view-mode--major-mode-hook (mode)
  (intern (concat (downcase (symbol-name mode))
                  "-hook")))
(defun major-mode-hook (mode-symbol)
  (intern (concat (downcase (symbol-name mode-symbol))
                  "-hook")))

(defun update-auto-view-mode-alist (mode directory)
  (unless (symbolp mode)
    (error "MODE should be a symbol."))
  (unless (file-exists-p directory)
    (error "%s dosen't exists." directory))
  (setq directory (directory-file-name (expand-file-name directory)))
  (and (if (assoc mode auto-view-mode-alist)
           (let* ((old-dirs (cdr (assoc mode auto-view-mode-alist)))
                  (new-dirs (if (equal directory old-dirs)
                                old-dirs
                              (if (consp old-dirs)
                                  (if (member directory old-dirs)
                                      old-dirs
                                    (cons directory old-dirs))
                                (list directory old-dirs)))))
             (unless (eq new-dirs old-dirs)
               (setq auto-view-mode-alist
                     (cons (cons mode new-dirs)
                           (rassq-delete-all old-dirs auto-view-mode-alist)))))
         (setq auto-view-mode-alist
               (cons (cons mode directory) auto-view-mode-alist)))
       (mapc #'(lambda (asc)
                 (add-hook (auto-view-mode--major-mode-hook (car asc))
                           'view-mode-with-auto-view-mode-alist))
             auto-view-mode-alist)))

(defun disable-auto-view-mode-alist (&optional mode)
  (setq auto-view-mode-alist
        (cond ((null mode)
               (mapc #'(lambda (asc)
                         (remove-hook (auto-view-mode--major-mode-hook (car asc))
                                      'view-mode-with-auto-view-mode-alist))
                     auto-view-mode-alist)
               nil)
              ((symbolp mode)
               (remove-hook (auto-view-mode--major-mode-hook mode)
                            'view-mode-with-auto-view-mode-alist)
               (assq-delete-all mode auto-view-mode-alist))
              (t (signal 'wrong-type-argument '(symbolp mode))))))

gist