全人類がやるべき設定その2です。
たとえば Perl 言語の設定は Perl のファイルを開くまで必要ないですし、Web ブラウザ eww の設定は eww を起動するまで必要ありません。それらを一度も使うことなく Emacs を閉じることがあれば、設定にかかった時間はまるまる無駄になってしまいます。
これを防ぐのが autoload
と with-eval-after-load
です。
正統派な使い方
autoload
の基本的な使い方は、主に以下の二つです。
- コマンドを提供するパッケージのロードを、そのコマンドが実行されるタイミングまで遅延する
- 特定の言語モードを拡張するパッケージのロードを、そのモードに入るタイミングまで遅延する
設定例を挙げます:
;; hoge パッケージを読み込む
(require 'hoge)
;; hoge パッケージの初期設定をする
(hoge-initialize)
;; hoge パッケージのコマンドにキーを割り当てる
(global-set-key (kbd "C-x h") 'hoge-run)
このようなコード片は、たいていの場合、次のように書き換えることができます。
;; hoge-run コマンドが実行されそうになったら慌てて hoge パッケージを読み込む
(autoload 'hoge-run "hoge" nil t)
;; hoge パッケージが読み込まれたらすぐに初期設定をする
(with-eval-after-load 'hoge
(hoge-initialize))
(global-set-key (kbd "C-x h") 'hoge-run)
書き換え後のコード片は、キーバインドの設定だけを起動時に行い、パッケージの読み込みは hoge-run
コマンドが実行されるまで遅延します。パッケージが読み込まれると、 with-eval-after-load
が hoge-run
の処理に移る前に割り込んで初期設定を実行するので、ほとんどの場合これで問題ありません。
この書き換えによって、 hoge-run
コマンドがそもそも使われなければ hoge
パッケージの設定はそもそも行われないし、仮に使うとしても起動時にすべてのパッケージの設定を行うよりはずっと起動時間が短くなります。
特定の言語だけで使用するパッケージなども同様に、トリガーだけを設定しておいて読み込みを遅延することができます。
(autoload 'sugoi-python-minor-mode "sugoi-python")
(add-hook 'python-mode-hook 'sugoi-python-minor-mode)
「起動時に必要とは限らないな」というパッケージに片っ端からこれを適用しましょう。突き詰めると、フォントやカラースキームの設定、ごく基本的なパッケージの読み込み(「かっこを光らせる」など)くらいしか、起動時に必須な設定はないことに気づくと思います。となれば当然、起動はかなり速くなります。
ところで自分はずっと with-eval-after-load
(eval-after-load
) の第一引数をファイル名の文字列にして使っていたのですが、
(with-eval-after-load "hoge"
'(hoge-initialize))
シンボル ('hoge
) にしておいた方がわずかに速いことに最近気づきました。前者はパッケージが読み込まれたかのチェックに正規表現を使うのに対して、後者はたんに eq
で比較されるためです。オーダーは変わらないですが定数倍が良いです。
自作関数も遅延する
ある自分で実装した関数があって、これがあるパッケージ foo
を利用している場合、次のように書くことで軽率に遅延することができます。
(autoload 'my-special-foo-command "foo" nil t)
(with-eval-after-load 'foo
(defun my-special-foo-command ()
...))
こう書いても微々たる差かもですが…。
(defun my-special-foo-command ()
(require 'foo)
...)
まとまった数の自作コマンドがある場合は、それらをまとめて別ファイルに移動してしまい、そのファイル全体をまるっと autoload
するのも手です。