Emacsのお手入れをする in 2019

新年初めのYak Shaving活動でEmacsのバージョンアップを行った。いい機会なので設定ファイルも見直すことにして、この先数年メンテしやすいよう、ほぼフルスクラッチでinit.elを書き直した。

Emacs 26.1 にアップデートした

これまで使っていた24.3からのアップデート。いろいろ壊れるかと心配だったけど、幸い引っかかったのはこの2点だけ。

どちらもリンク先のお陰でラクに対応できた。

.emacs.d下のconfig分割をやめた

設定見直しの第一歩として、細かく分割していた設定ファイルをinit.elに統合した。元々はinit-loaderを使っていた名残で、以下のようにファイルを分割していた。

.emacs.d/init.el # el-getでインストールするパッケージ一覧を記述 .emacs.d/vendor/packages.el # ジャンルごとに設定ファイルを分割 .emacs.d/config/general.el .emacs.d/config/languages.el .emacs.d/config/git.el ...

init.elに統合したのは、

  • 編集時に複数のファイルを行ったり来たりするのが面倒
  • どこに書くべきか迷った挙句、general.el にぶち込む事がある
  • ファイルの読み込み順序を意識して書かないとロードエラーになるのが難しい

などの理由から。設定を分けたことで返って負担を感じることが多かった。

そもそもファイルを分けるほど設定が肥大化し、読みづらくなってることが根本の問題だし、今回は設定のダイエットと可読性の向上により根本的な解決を目指した。

init.elは最小限の設定だけ書いた

10年近く継ぎ足してる秘伝のタレなので、書いた当初は必要だったけど今は不要だったり、そもそも機能していないものが幾つかあった。

以下を念頭に置きながら片っ端から断捨離した。

  • 消すと今すぐ困るもの以外消す。必要になったら復活させる
  • コードはIDEで書く前提で、プログラミング系拡張は基本的なもの以外消す
  • 動作環境はmacOS・最新VersionのEmacsだけを想定して、分岐をなくす

今だとコードはIDEで書くことが多いので、プログラミング環境はそれらに任せることで設定がだいぶスッキリした。今は各言語のマイナーモードなど基本的なパッケージだけ残っている。

用途不明のsetqとかも一つづつ潰していった。List of Emacs Lisp Variables にもあるように、ビルトイン変数であれば M-x apropos-variable で設定値の役割が調べられる。しかし使わなくなったthird partyライブラリ用の変数も多くて、結局一つづつググりながら不要なものを消していった。

あとは昔サーバサイド・インフラを触っていた名残でLinux環境も考慮した設定が残っていたけど、今は手元のmacOSだけでEmacsを動かすので環境による分岐設定を削除。

el-getからuse-packageへ移行した

el-get から package.el + use-package に完全移行した。移行した第一のモチベーションは、パッケージ管理のような機関部分は最もスタンダードな構成に寄せていきたかったから。

init.elの冒頭に書くパッケージ初期化フローも簡潔になった。たったこれだけ書けば動く。

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-when-compile
  (require 'use-package))

第二のモチベーションはinit.elの可読性向上。以下は自分のhelm設定だけど、use-packageを使うことでパッケージ読み込みとカスタマイズを一箇所で、宣言的に記述できる。

(use-package helm
  :init
  (setq helm-ff-file-name-history-use-recentf t)
  (setq helm-display-function #'display-buffer)
  :bind
  (("M-x" . 'helm-M-x)
   ("C-x C-f" . helm-find-files)
   ("C-x C-r" . helm-for-files)
   ("C-x C-y" . helm-show-kill-ring)
   ("C-x C-b" . helm-buffers-list)
   :map helm-map
   ("C-h" . delete-backward-char)
   :map helm-find-files-map
   ("C-h" . delete-backward-char)
   ("TAB" . helm-execute-persistent-action)
   :map helm-read-file-map
   ("TAB" . helm-execute-persistent-action))
  :config
  (helm-mode 1))

init.elの冒頭で (setq use-package-always-ensure t) と書いておけば、宣言したパッケージを必要に応じて自動インストールしてくれる。複数マシンで設定ファイルを共有する際も簡単。

最終形

最終的に200行程度に収まった。行数的にはまだ結構あるけど、全体的な見通しがよくなって読んでいても苦にならない。

dotfiles/init.el at master · horimislime/dotfiles

所感

Emacsのバージョンアップとともに設定を刷新した。一度ゼロベースで考え直したことで改修のしやすいinit.elになった。

Emacsといえばelispが辛い、設定で疲弊するもの、みたいな風潮がある。けど疲弊の根本理由はいらないことをやり過ぎている、ネットで拾ってきた古くて今なら楽な記法があるコードを使ってしまっている、など色々あると思う。長くinit.elをメンテして疲れ気味なら、一度最小構成にしてモダンな手法を取り入れたらだいぶ変わるかもしれない。elispが辛いのはどうしようもないので頑張りましょう。

Tweet