Emacsの設定: 雑多なものはCustomize、理由を残したいものはsetoptを使う

Emacsの設定を書いていると、 setqsetoptcustom-set-variables のあたりで、だんだん話がややこしくなってくる。普通の変数は setq でよさそうに見えるし、 M-x customize は便利だし、 defcustom で定義された変数には専用のやり方がありそうにも見える。

実際、それぞれの役割は少しずつ違う。しかも Customize を使い始めると、保存先の custom-set-variables は Emacs によって自動更新されるので、その中に長いコメントやメモを書き込みにくい。設定値はここに保存したいが、設定理由は別に残したい、という気持ちになる。

普通の変数は setq 、現在のバッファだけに効かせたいものは setq-local 、バッファローカル変数のデフォルト値は setq-defaultdefcustom で定義されたユーザーオプションは主に setopt 、必要に応じて customize-set-variable を使う、という分け方でおおむね良いだろう。 custom-set-variables は自分で育てる設定というより、 Customize が保存する領域として custom-file に分けておく方が扱いやすい。

この記事では、そのあたりをどう整理して、コメントを書きたい設定と Customize に任せたい設定をどう分けるのが扱いやすいかを考えてみる。

それぞれの役割

Emacsの設定には、見た目は似ていても役割の異なる書き方がいくつかある。

defvar

defvar は、変数を定義するための仕組みだ。主に Lisp 側で「この名前の変数を使う」と宣言する時に使われる。

(defvar my-cache-directory "~/.cache/my-app")

これは利用者に Customize で変更してもらうための宣言というより、プログラム側が使う変数を用意するためのものだ。

defcustom

defcustom も変数を定義するが、こちらは利用者が Customize 経由で設定する事を前提としたユーザーオプションを定義する時に使う。

(defcustom my-enable-feature t
  "Whether to enable my feature.")

defcustom で定義された変数は、 M-x customize から見つけやすく、型や説明文、専用の setter などを持てる。 setoptcustomize-set-variable が話題に出てくるのは、こういう変数を設定する時だ。

setq

setq は、現在見えている変数束縛に値を設定するための基本手段だ。

(setq indent-tabs-mode nil)

普通の変数を init.el で設定する時は、まずこれを考えればよい。

setq-local

setq-local は、現在のバッファだけで有効なバッファローカル変数として値を設定する時に使う。

(setq-local fill-column 72)

setq と違って、他のバッファには影響しない。その場限りのバッファ単位の設定を書きたい時はこちらを使う。

setq-default

setq-default は、主にバッファローカル変数のデフォルト値を設定するために使う。

(setq-default tab-width 4)

setq と似ているが、意味は少し違う。 setq はその場の値を変えるのに対し、 setq-default は新しいバッファでも参照されるデフォルト値を変える。

setopt

defcustom で定義されたユーザーオプションを手で設定するなら、最近は setopt が分かりやすい。

(setopt ring-bell-function 'ignore)

setopt は Custom 用の setter を通せる事があるため、 setq より適切な場合がある。

customize-set-variable

customize-set-variabledefcustom な変数を設定する関数だ。

(customize-set-variable 'ring-bell-function 'ignore)

最近の init.el では setopt の方が自然に見える事が多いが、次のような時には customize-set-variable を使う理由がある。

  • 古い Emacs との互換性を意識したい時
  • Custom の流儀で設定している事を明示したい時
  • 既存の設定ファイルがすでにこの書き方で統一されている時

custom-set-variables

custom-set-variables は、普段自分で書くための関数というより、 M-x customize が設定を保存する時に書き出すブロックだ。

(custom-set-variables
 '(ring-bell-function 'ignore)
 '(tab-width 4))

これは人間が説明を書き足しながら育てる形式というより、Emacsが機械的に更新する保存形式として扱う方がしっくりくる。

Customizeを使いたいが、コメントも残したい

僕が困るのはここだ。基本的には Customize を使いたい。UIで値を試せるし、 defcustom な変数を探しやすい。しかし保存先の custom-set-variables は自動更新されるので、その中に長いコメントや補足を書きにくい。

もちろん短いコメントなら何とかなる場合もある。しかし、設定理由や比較した選択肢、試した結果、注意点のような長いメモを残したくなると、急に扱いづらくなる。自動生成される領域なので、人間向けの注釈を書く場所としては落ち着かない。

この問題は、 Customize が悪いというより、 custom-set-variables が「機械が更新する保存形式」だから起きる。

うまい運用

いちばん扱いやすいのは、値と理由を分ける事だ。

  • 値そのものは Customize に保存させる
  • 保存先は custom-file に分離する
  • 設定理由や長いメモは init.el や別の Org/Elisp ファイルに書く
  • コメント込みで管理したい設定だけは、 setoptcustomize-set-variable で手書きする

たとえば、まず M-x customize で設定を試し、気に入ったものだけを後で手書き設定へ昇格させる、という流れがある。

(setq custom-file (expand-file-name "~/.emacs.d/custom.el"))
(load custom-file t)

このように custom-file を分けておけば、 init.el は人間が読む設定、 custom.el はEmacsが書く設定、という役割分担ができる。

手書き設定へ昇格させる

ある変数について、値だけではなく理由も残したくなったら、その変数は手書き設定へ移した方がよい。

;; テーマによってはベルが激しくて気になるため無効にする
(setopt ring-bell-function 'ignore)

こうしておけば、なぜその値なのかを隣に書ける。あとから見返した時にも理解しやすい。

逆に、 custom-set-variables の中へ同じ事を書こうとすると、自動更新で壊れやすいし、読み物としてもつらい。

二重管理を避ける

ただし、手書き設定へ昇格させた時に気をつけたい事がある。 setoptcustomize-set-variable で手書きした変数が、同時に custom-filecustom-set-variables にも残っていると、同じ変数を二重管理する事になる。

この状態だと、どちらが最後に読み込まれるかで値が決まる。いったんは動いても、後から読むと分かりにくいし、将来の自分も混乱する。

なので、コメント付きで手書きに昇格させた変数は、 custom-file 側から消した方がよい。

運用としては、次のように分けるのが楽だ。

  • 雑多で機械的な設定は Customize に任せる
  • 理由を残したい設定は手書きする
  • 同じ変数を両方で持たない

さらに、手書き設定と custom-file に同じ変数名が出ていないかを、定期的に確認できるようにしておくと安心だ。

結局どう扱えばいいのか

今のところ、僕には次の方針がいちばんしっくりくる。

  • 普通の変数は setq
  • 現在のバッファだけに効かせたい時は setq-local
  • バッファローカル変数のデフォルト値は setq-default
  • defcustom な変数を手で設定する時は setopt を第一候補にする
  • 古い Emacs 互換や既存流儀を優先する時は customize-set-variable を使う
  • custom-set-variables は自分で育てる設定ではなく、Customizeが保存する領域として分離する
  • コメントを書きたい設定は手書きに移し、 custom-file 側には残さない

Customize を使うのをやめる必要はない。ただし、 custom-set-variables に人間向けの説明責任まで持たせようとすると窮屈になる。値の保存はEmacsに任せ、理由の記述は手書きの設定に寄せる、という分担の方がずっと扱いやすい。

作成日
更新日
更新日
最終更新日