Emacs auto-minor-mode based on extension

2020-05-31 16:27发布

问题:

I found this question somewhat on the topic, but is there a way [in emacs] to set a minor mode (or a list thereof) based on extension? For example, it's pretty easy to find out that major modes can be manipulated like so

(add-to-list 'auto-mode-alist '("\\.notes\\'" . text-mode))

and what I'd ideally like to be able to do is

(add-to-list 'auto-minor-mode-alist '("\\.notes\\'" . auto-fill-mode))

The accept answer of the linked question mentions hooks, specifically temp-buffer-setup-hook. To use this, you have to add a function to the hook like so

(add-hook 'temp-buffer-setup-hook #'my-func-to-set-minor-mode)

My question is two-fold:

  1. Is there an easier way to do this, similar to major modes?
  2. If not, how would one write the function for the hook?
    1. It needs to check the file path against a regular expression.
    2. If it matches, activate the desired mode (e.g. auto-fill-mode).

Feeble and buggy attempt at a solution:

;; Enables the given minor mode for the current buffer it it matches regex
;; my-pair is a cons cell (regular-expression . minor-mode)
(defun enable-minor-mode (my-pair)
  (if buffer-file-name ; If we are visiting a file,
      ;; and the filename matches our regular expression,
      (if (string-match (car my-pair) buffer-file-name) 
      (funcall (cdr my-pair))))) ; enable the minor mode

; used as
(add-hook 'temp-buffer-setup-hook
          (lambda ()
            (enable-minor-mode '("\\.notes\\'" . auto-fill-mode))))

回答1:

This code seems to give what you want:

(defvar auto-minor-mode-alist ()
  "Alist of filename patterns vs correpsonding minor mode functions, see `auto-mode-alist'
All elements of this alist are checked, meaning you can enable multiple minor modes for the same regexp.")

(defun enable-minor-mode-based-on-extension ()
  "Check file name against `auto-minor-mode-alist' to enable minor modes
the checking happens for all pairs in auto-minor-mode-alist"
  (when buffer-file-name
    (let ((name (file-name-sans-versions buffer-file-name))
          (remote-id (file-remote-p buffer-file-name))
          (case-fold-search auto-mode-case-fold)
          (alist auto-minor-mode-alist))
      ;; Remove remote file name identification.
      (when (and (stringp remote-id)
                 (string-match-p (regexp-quote remote-id) name))
        (setq name (substring name (match-end 0))))
      (while (and alist (caar alist) (cdar alist))
        (if (string-match-p (caar alist) name)
            (funcall (cdar alist) 1))
        (setq alist (cdr alist))))))

(add-hook 'find-file-hook #'enable-minor-mode-based-on-extension)

Note: the comparison is done with string-match-p which follows the case-fold-search settings during comparison.



回答2:

The answer by Trey Jackson seems to be a very robust and extensible solution, but I was looking for something simpler. The following code will enable the fictional hmmm-mode when editing .hmmm files:

(add-hook 'find-file-hook
          (lambda ()
            (when (string= (file-name-extension buffer-file-name) "hmmm")
              (hmmm-mode +1))))