很多人的配置文件,各種主模式的配置寫在一起的,可能既有 c 又有 lisp 又有 js 什麼的,其實大部分情況下你不會同時用那麼多。
於是有了另一種方式,拆分到文件,每種模式用一個單獨的文件。在主配置文件里寫上 (load 'xxx)
但是這挺麻煩的,你要新建一個文件名為 xxx,然後主配置文件里又得寫 load xxx,這顯然是重複勞動……這是我最痛恨的……因為我一年級就上了好幾次
於是我弄了一個文件夾,按順序自動 load 裡面的文件,當然不是隨便 load,得符合條件才行。比如我設定的條件是擴展名為 el。
這樣一來,不想 load 的文件改下擴展名就可以了……我還弄了一個函數,專門給文件添加/刪除擴展名 .bak 但是時間長了也挺麻煩的,因為要手動改,而且下次才能生效…… 你還得自己 load-file
……其實一般情況下,這不是什麼問題,你就是給每種模式寫上幾萬行的配置,都寫在一個文件里,對於現在的機器而言,壓力也不是太大……但是咱追求的不是方便,而是折騰
好了,開始動手
(let (name (dir (expand-file-name "_major-mode/" *init-dir*))) (mapcar (lambda(x) (setq name (file-name-sans-extension (file-name-nondirectory x))) (add-hook (concat-symbol name "-mode-hook") `(lambda()(load ,x)))) (directory-files dir t "\\.el\\'")))簡單的說,假設 ~/init.emacs/_major-mode/ 目錄下有 3 個文件 emacs-lisp.el nxml.el js2.el.bak ,則會:
在 emacs-lisp-mode-hook 里添加 (lambda nil (load "~/init.emacs/_major-mode/emacs-lisp.el"))
在 nxml-mode-hook 里添加 (lambda nil (load "~/init.emacs/_major-mode/nxml.el"))
裡面用到的 concat-symbol
(defun concat-symbol (&rest lst) (read (apply 'concat (mapcar (lambda(x)(if (symbolp x) (symbol-name x) x)) lst))))需要注意的是,這簡直就是一個特大號的 hook ,所以不用在裡面再寫什麼 add-hook 'xxx-mode-hook 了,裡面所有的東西都相當於在 xxx-mode-hook 里。
如此一來,就產生了另一個問題,每打開一個 a.xxx 文件,xxx-mode-hook 就要運行一次,然後 load 一次,真二,實際上只要 load 一次就可以了。
這個問題可以用 require 來解決,但缺點是,你要在新建一個文件為 xxx.el ,還要在裡面寫 provide 'xxx ,並且還要把當前目錄加到 load-path,重複勞動還是比較多。
另一種方案就是 load-once
(defmacro load-once (&rest s) (let* ((name (file-name-sans-extension (file-name-nondirectory (or load-file-name (buffer-file-name))))) (a (concat-symbol "*load-once--" name "*"))) `(if (boundp ',a) nil ,@s (setq ,a t))))
在 xxx.el 裡面只運行一次的部分可以寫在 load-once 裡面,像這樣
(load-once (foo) (bar) )基本上,你把所有內容都寫在 load-once 裡面就對了,不管這個文件被 load 了多少次,都只運行一次。
這種方法的缺點是,需要在文件開頭和結尾分別寫 (load-once 和 ),而 provide 只要寫在一處; 每種模式被 load 后,自動生成了一個值為 t 的變數 *load-once--xxx* 、*load-once--yyy* ……
所以,我覺得我有責任給你一個十分專業的建議:你自己看著辦
我的配置文件
或者也可以根據 buffer-name 來判斷
(let* ((dir (expand-file-name "_extensions/" *init-dir*)) (ext (mapcar (lambda(x)(cons (file-name-sans-extension (file-name-nondirectory x)) x)) (directory-files dir t "\\.el\\'")))) (add-hook 'find-file-hook `(lambda () (load (or (cdr (assoc (or (file-name-extension (buffer-name)) (and (string-equal "*" (substring (buffer-name) 0 1)) (substring (buffer-name) 1 -1))) ',ext)) (make-temp-name "")) t))))假設在 init-dir/_extensions/ 目錄下文件為: xml.el el.el js.el eshell.el
普通文件通過擴展名來載入配置,xxx.js -> load js.el
以 * 開頭的臨時文件則去掉第一個和最後一個字元后,通過得到的名字來載入配置,eshell -> load eshell.el
[火星人 ] emacs 小技巧:根據主模式載入配置已經有387次圍觀