Emacsの起動時間を短縮する方法 #Emacs #AdventCalendar
すみません書くのがものすごく遅れてしまいました...。なんとか年内に書けた...。
前の日は、color-themeでEmacsの見た目をきれいにする - Qiita、
次の日は、emacsの設定ファイルをどうするかというのはおそらく共通の悩み - Qiita
です。
はじめに
Emacsをずっと使い続けていると様々な言語の設定や、Emacsの挙動を少し変える設定を付け加えたりと、設定がどんどん増えていきます。多く書きすぎると遅くなるのでかなりストレスフルになってしまいます。これはautoloadや、eval-after-loadを使えばかなり軽減することができます。
しかし、autoloadとeval-after-loadだと、慣れないとどの関数を設定すればいいか全くわからない状況に陥ってしまいがちです。さらに設定ファイルも煩雑になりがちです。
これを解決できるマクロで深町さんが紹介してるlazyloadというものがあります。
http://e-arrows.sakura.ne.jp/2010/03/macros-in-emacs-el.html
このマクロはautoloadとeval-after-loadが隠蔽されているのでだいぶ書きやすいという利点があります。この記事ではそのlazyloadを使った起動時間短縮のための設定を紹介します。
設定のやり方
使うマクロはこれです。
;; (lazyload (triger-function ...) "filename" &rest body) (defmacro lazyload (func lib &rest body) `(when (locate-library ,lib) ,@(mapcar (lambda (f) `(autoload ',f ,lib nil t)) func) (eval-after-load ,lib '(progn ,@body)) t))
使い方はorg-modeを例にして説明します。
設定の仕方は、
の3つの設定をやっていきます。
1つ目は、auto-mode-alistに拡張子の登録と、トリガーとなる関数のキーバインドを設定しておきます。メジャーモードなどの場合登録しておかないと「◯◯.拡張子」のファイルを開いても意図したモードになってくれません。
トリガーとなる関数のキーバインドを設定しておくと、関数を読み込んだ時に設定が読み込まれるようになります。
マイナーモードや追加機能の場合はキーバインドの設定のみで大丈夫だと思います。
共通のパスの設定もlazyloadの外でやっておくといいです。
;; Dropboxのパス変数 (defvar dropbox-directory (cond ((equal system-type 'windows-nt) (concat "c:/Users/" user-login-name "/Dropbox")) (t "~/Dropbox"))) ;; 拡張子の登録 (add-to-list 'auto-mode-alist '(".org$" . org-mode)) ;; キーバインドの設定 (global-set-key "\C-cl" 'org-store-link) ;; (global-set-key "\C-cc" 'org-capture) (global-set-key "\C-ca" 'org-agenda) (global-set-key "\C-cb" 'org-iswitchb) ;; C-c r でorg-remember起動 (define-key global-map (kbd "C-c r") 'org-remember)
次にlazyloadの設定をします。ここでは(function ...)部分にトリガーとなるメジャーモードの関数や、キーバインドで設定した関数を入れていきます。こうすると◯◯.orgのファイルが読み込まれた時や、最初に設定したキーバインドが読み込まれた時に設定が読み込まれて起動時間を短縮できます。
filename部分は基本的に各メジャーモード、マイナーモード、追加機能のファイル名(拡張子なし)を入れておけばよいですが、org-modeの場合はorg-installが起点となるファイルになります。
body部分はフックを除いた設定、requireなどをどんどん入れていけば良いです。
;; lazyloadの設定 ;; (lazyload (function ...) "filename" &rest body) (lazyload (org-mode org-install org-store-link org-agenda org-iswitchb org-remember) "org-install" (require 'org-install) (defvar org-foo) (defun org-bar () ...) (define-key org-mode-map "\M-n" 'org-next-visible-link) (define-key org-mode-map "\M-p" 'org-previous-visible-link) ... )
最後に、lazyloadの後ろにフックの設定をしておきます。org-modeには特に設定するものがなかったのでfoo-functionというのを例にしています。lazyloadの中にhookを設定しておくとうまく動かないので、外で設定してください。
;; フックの設定 (add-hook 'org-mode-hook 'foo-function)
これで設定は終了です。
完成した設定例が下のコードです。
設定例
;;;;;;;;;;;;;;;;;;; ;; 設定例 org-mode ;; 共通のパス変数はlazyloadの外で宣言しておく ;; Dropboxのパス変数 (defvar dropbox-directory (cond ((equal system-type 'windows-nt) (concat "c:/Users/" user-login-name "/Dropbox")) (t "~/Dropbox"))) ;; 拡張子の登録 (add-to-list 'auto-mode-alist '(".org$" . org-mode)) ;; キーバインドの設定 (global-set-key "\C-cl" 'org-store-link) ;; (global-set-key "\C-cc" 'org-capture) (global-set-key "\C-ca" 'org-agenda) (global-set-key "\C-cb" 'org-iswitchb) ;; C-c r でorg-remember起動 (define-key global-map (kbd "C-c r") 'org-remember) ;; lazyloadの設定 ;; (lazyload (function ...) "filename" ...) (lazyload (org-mode org-install org-store-link org-agenda org-iswitchb org-remember) "org-install" (require 'org-install) (if (boundp 'dropbox-directory) (setq org-directory (concat dropbox-directory "/Documents/org/"))) (setq org-default-notes-file (concat org-directory "agenda.org")) (setq org-mobile-directory (concat dropbox-directory "/MobileOrg")) (setq org-mobile-inbox-for-pull (concat dropbox-directory "/flagged.org")) (setq org-agenda-files (mapcar #'(lambda (x) (concat org-directory x)) '("work.org" "school.org" "home.org"))) (defvar org-foo) (defun org-bar () ...) (define-key org-mode-map "\M-n" 'org-next-visible-link) (define-key org-mode-map "\M-p" 'org-previous-visible-link) ... ) ;; フックの設定 (add-hook 'org-mode-hook 'foo-function)
lazyloadを使った結果
Windowsでlazyloadを使った時の結果を表示します。このときの設定は確か
だったと思います。(すみません来月補足します。)
下の結果はinit-loader.elを使った起動時間のログになります。lazyloadを使用した結果、ものによっては1秒近くかかっていた設定が0.001秒まで減るのでかなりの起動時間の短縮になります。頻繁に使うモードでもlazyloadをしておけば起動時間をかなり短縮することができます。
org-mode 0.921318 org-mode 0.005438999999999999 howm 0.26786200000000004 howm 0.002473 sequential-command 0.735374 sequential-command 0.0016799999999999999 e2wm 0.136477 e2wm 0.001269 ruby-mode.elc. 0.01617600000000008 ruby-mode.elc. 0.021811999999999998
この結果でruby-modeのみ若干時間がかかっていますが、これはすでにeval-after-loadなどで囲まれていたものをlazyloadに変更したので時間がかかっています。しかし、見た目がかなりすっきりして設定もしやすいのでlazyloadを使ったほうが楽です。
終わりに
これを使えばそこまで設定を削らずに設定を残すことができ、比較的楽にautoload,eval-after-loadの設定ができるので、使うと便利です。起動時間が長くて困っている人で、「autoloadとかわからない」という人はlazyloadを使ってみましょう。