.emacs.dを整理した

先日、会社でサービスをリリースして仕事が一段落したので、そのタイミングで.emacs.dを一気に整理した。

普段emacsを使ってるのだけど、新しい拡張入れたくなった時に各環境で別個に入れていったら、自宅と会社の開発環境に乖離が生まれてきて、だんだん嫌になってきたので.emacs.dを整理して、各環境間で同期しやすい状態にした。この記事は、.emacs.dを整理した話しか書いてない。実際に使ってる便利な拡張の話はまた別途記事にする予定。

f:id:ainame:20131025185729p:plain

そもそもなぜ同期できなかったか?

普段社内では、社内でPerl書く時専用の拡張などを利用しているため、githubに直接.emacs.dを全部上げるなどが出来ず、かといってprivateなリポジトリに全部置いたとしても自宅環境ではその専用拡張は必要ない。また、専用拡張まで行かなくても、たとえばmigemoのパスとか完全に同じ設定を使えない箇所があったりした。

gitで設定ファイルを管理しようとしたものの、最初、そのような環境依存の拡張をブランチ切り替えで対応しようとしていて、更新していくのが限界になってリモートリポジトリに反映していくのをやめた。

やめた途端、どんどん家と会社で環境が変わっていって日々最悪なエディタ体験を味わう事となった。

整理

↓に整理後のリポジトリを置いといた。 https://github.com/ainame/emacs-d

整理にはいくつかコツがあったので書いておく。大きく分類すると以下の2つの方針で今回は整理した。

  1. 旧設定・新設定を簡単に切り替えられるようにしておく
  2. 環境依存・読み込み順番依存部分を可能な限り排除する

1. 旧設定・新設定を簡単に切り替えられるようにしておく

emacsの設定ファイルを書くときにvimを使う人はそんなに居ないと思う。でも、.emacs.dを大幅に変更しようとした時に中途半端な設定のemacsでemacs lispはあんまり書きたくない。これはemacs設定をいじるときに結構みんな困ってるような気がすることだと思う。

そこで、ちょっとずつ.emacs.dの設定を移行するために旧設定・新設定を簡単に切り替えられるようにしておくと良い。自分は特定のディレクトリに古い.emacs.dをコピーしておいて、~/.emacs.dにシンボリックリンクを置いて、その参照先を変更できるようにrakeタスクを書いておいた。

↓のような感じ

$ rake copy     # copy ~/.emacs.d into `pwd`/old
$ rake new      # create symbolic link to `pwd`/src
$ rake old      # you can revert src settings

それ意外にもemacsには起動時のオプションで読み込みelファイルを指定できるので以下のようにemacsを起動しても新しい設定を確認できる。

$ emacs -Q -L /path/to/load-path -l /path/to/new/init.el

↑のような起動の仕方をした時に、init.elなどで追加でロードパスを~/.emacs.dベースのパスで指定すると、正しくないパスとして扱われてしまう点だ。

(add-to-list 'load-path "~/.emacs.d/el-get/el-get")

とやってしまうと、シンボリックリンクを~/.emacs.dに置いてない時は、正しく解釈されない。 この場合、user-emacs-directoryという変数の値を基準にパスを設定できるようにすると良い。

(defun my-abs-path (path)
  (expand-file-name (concat user-emacs-directory path)))
(add-to-list 'load-path (my-abs-path "el-get/el-get"))

というように書いたほうが変に困らなくて便利。

2. 環境依存・読み込み順番依存部分を可能な限り排除する

emacsの設定を書くときに次に困るのは環境とか設定ファイルを分割した時の読み込み順番依存の問題とかだと思う。

init-loader.elっていう便利な拡張があるのだけど、これは設定ファイルのファイル名をいろいろ頑張ることで、emacsの種類ごとにファイルを読みこませることが出来たり、ファイル名の先頭に付けた順番通りに拡張を読みこませることが出来る。

だけど自分は使ってない。理由としては、

  1. 若干起動が重くなる気がする(すぎゃーんさんのブログを読んで知った http://d.hatena.ne.jp/sugyan/20120104/1325683745)
  2. ファイルの番号管理が嫌い(読み込み順番問題の根本解決にはなってないしメンテ辛い)
  3. emacsは基本的にターミナルの中でしか使ってないのでGUIごとの依存がない

ってのがある。

あと、番号設定ファイルをガシガシ書いておいて、その中でどんどんrequireしいくと、しなくていい時にrequireされてしまう。これはpackage.el以降のautoloadの仕組みがもったいない気がしている。(毎回eval-after-loadとか使って書けばいいのだけど)

なので、自分はinit-loader.elを使わずに以下のような方法で設定を読み込ませてる。

el-getで落とす拡張に依存しない設定は、personal-dirに保存して*.elcファイルだけを読み込む

これはめっちゃシンプルで、指定したディレクトリ以下のコンパイル済みの設定ファイルだけをひたすら読み込むだけ。読み込み順番についてはrequireをほぼ書かないで済む設定しか置かないことで解決。

(defvar personal-dir (my-abs-path "personal-conf"))

(when (file-directory-p personal-dir)
  (mapc 'load (directory-files personal-dir 't "^[^#].*elc$")))
el-getで落とす拡張に依存する設定は、el-get-user-package-directoryに保存して読み込む

el-getのデフォでは有効になってない設定の1つにPackage Setup機能がある(READMEに書いてある)。el-get-user-package-directoryという変数があって、この変数にパスを指定しておくと、そのディレクトリ以下にinit-<package name>.elと名づけたファイルを置くことで、(良い感じのタイミング)https://github.com/dimitri/el-get/blob/master/el-get.el#L545で読み込まれるようになる。

読み込まれる順番でエラーが起きたりするような問題は基本的に各パッケージをrequireすることで起きると思うので、自分ではrequireは極力書かずに必要な時のみ書くようにする。基本的にはel-get使ってるのでautoloadが設定されるので自分でrequireすることはないけど、たまにうまくいかない時があるので動かなかったら自分でrequire書いてとりあえず回避するぐらいのノリで設定を書いてる。

どうしても環境に依存してしまうファイルは.gitignoreに追加したファイルに追加する

自宅ではMac、会社の開発環境では管理者権限がない非MacのOSみたいなときに、migemoとかを設置するパスの問題が発生すると思う。そういうどうしようもないやつは最低限にしぼって.gitignoreに追加したファイルに定義する。最低限っていうのは、たとえばmigemoの例だと、migemoの設定全体は共通化しておいて、migemoのパスだけ別ファイルの変数を参照するようにしておくとかそういう感じ。

ただ、何もファイルが存在してないと他のマシンに入れようとした時に設定思い出すの辛いので.sampleファイルみたいなのは用意しておく。 https://github.com/ainame/emacs-d/blob/master/src/init/my-environment.el.sample

あとは↑のファイルには、社内専用の拡張にまつわる設定も書いたりしていた。

まとめ

ネット上見る限り、日本人は結構init-loader.elを使ってる人が多くて、自分の場合、init-loader.elを使わずに設定してい若干珍しい感じになっていると思うけど、こういう設定の仕方も出来るんだよ〜みたいなことが言いたかった。emacsの設定は拡張続けるといつか壊れて何が原因でそうなったのか分からない事が多かったり、拡張入れすぎて何がなんだか分からなくなったりすることがあるので、年に1回ぐらい設定ファイルを見直して整理するのはいいかな−と思った。今回、できる限りいろんな依存関係をできる限り排除した設定を心がけたので、次に何か拡張しようと思った時には、やりやすい感じになっていると思う。

あと、emacs24になってpackage.elが使えるようになったので、整理すると整理前に使ってた拡張をバージョンアップするのがすごく楽なので、ガンガン最新の機能が使えるようになった。特にemacsのgitツールのmagitはバージョンアップしたら機能増えまくっていてめっちゃ便利になってた。

こんな感じで僕の考えた最強の.emacs.dみたいなものが出来上がったのだけど、バッドノウハウの塊みたいな感じなので、みんな素直にSublime textとかEclipseとかもっと使えばいいと思う。

Emacs Lispテクニックバイブル

Emacs Lispテクニックバイブル