init.elの設定をコンピューターごとに分岐させる


Emacsの大きな特徴の一つは、Mac OS X、Linux、Windowsなどといった異なったOSでも、同じUI、ほぼ同じ設定で使えることだと思っています。

とはいえ、OSなどの環境ごとに設定を切り替える必要がある部分や、切り替えた方が便利な部分があることも事実。ここでは、init.el（.emacs）の設定をOSなどの環境に合わせて切り替える方法を考えます。

## 切り替えに使う変数 ##
### system-type変数 ###
`system-type`変数を使うと、OSごとに設定を切り替えられます。主なOSの種類は次のとおり。

* gnu/linux
* darwin
* windows-nt

詳細は、`C-h v`（`describe-variable`）で`system-type`を調べてください。

たとえば、次のようなMac OS Xだけで有効な設定を~/.emacs.d/init-darwin.elファイルに記述したとします。

```
;; Mac OS X用の文字コード指定
(setq file-name-coding-system 'utf-8-hfs)
(setq locale-coding-system 'utf-8-hfs)
```

この設定は、init.elに次の記述をすることでMac OS Xの場合だけ、呼び出すことができます。LinuxやWindowsなど、Mac OS X以外のOSの場合は呼び出しません。

```
(when (equal system-type 'darwin)
  (load-file "~/.emacs.d/init-darwin.el"))
```

### window-system変数 ###
`window-system`変数は、ウインドウシステムごとに設定を切り替えられます。主なウィンドウシステムの主な種類は次のとおり。

* nil
* x
* w32
* mac
* ns

詳細は、`C-h v`で`window-system`を調べてください。

Mac OS Xの場合はmacの場合が多いと思うのですが、nsの場合もあるかもしれません。自分のEmacsで調べるには`ESC-:`（`eval-expression`）で`window-system`を評価してください。

たとえば、次のようなMac OS XのEmacsアプリ（非ターミナル）だけで有効にしたい設定を~/.emacs.d/init-mac-gui.elファイルに記述したとします。
ここでは、環境変数およびexce-path、フレーム、フォントなどを設定しています。

```
;; Mac OS Xのpath_helperでPATHを取得し、あらためてPATHとして設定
(let ((shell-file-name "/bin/bash"))
    (setenv "PATH"
            (shell-command-to-string
             "eval $(/usr/libexec/path_helper -s) && printf $PATH")))

;; Emacs変数exec-pathに、環境変数PATHの内容を設定
(setq exec-path nil)

(dolist
    (dir (split-string (getenv "PATH") "[:\n]"))
  (when (file-directory-p dir)
    (add-to-list 'exec-path dir t)))

;; 標準のフォントサイズとフォントファミリーの設定
(set-face-attribute 'default nil
                    :height 120
                    :family "Menlo")

;; キャラクターセットごとにフォントファミリーを設定
(dolist
    (list
     '(
       (jisx0201 "Osaka")
       (japanese-jisx0213.2004-1 "Hiragino Kaku Gothic ProN")
       (japanese-jisx0213-2 "Hiragino Kaku Gothic ProN")
       ))
  (let ((charset (car list))
        (fontfamily (nth 1 list)))
    (cond
     ((not (member charset charset-list))
        (message "Character set %s is not found." charset))
     ((not (member fontfamily (font-family-list)))
        (message "Font family %s is not found." fontfamily))
     ((set-fontset-font t charset (font-spec :family fontfamily))))))

;; フレームの設定
(dolist
    (val
     '(
       (foreground-color . "black")
       (background-color . "gray99")
       (cursor-color . "DarkOliveGreen")
       (cursor-type . box)
       ))
  (add-to-list 'default-frame-alist val))

;; commandキーをEmacsのMetaキーに
(setq mac-command-modifier 'meta)

;; ミニバッファにカーソルを移動する際、自動的にキーボードをASCIIモードにする
(mac-auto-ascii-mode 1)

;; Mac OS Xのキー設定
(dolist
    (map
     '(
       ("<M-f1>" other-frame)    ; Mac OS Xの他アプリと同様に、command + F1でアプリケーションの次のウィンドウを操作対象にする
       ))
  (let ((key (car map)) (func (nth 1 map)))
    (if (not (functionp func)) (message "%s is not defined." func)
      (global-set-key (kbd key) func))))

(cd "~")
```

この設定は、init.elに次の記述をすることで呼び出すことができます。

```
(when (equal system-type 'darwin)
  (load-file "~/.emacs.d/init-mac-gui.el"))
```

`system-type`と`window-system`の違いは、コンソール（端末）上でEmacsを使う場合にあらわれます。

たとえばMac OS Xで`system-type`は、コンソール上のEmacsでもEmacsアプリでも`darwin`です。一方`window-system`は、コンソール上のEmacsではnil、Emacsアプリでは`mac`（または`ns`）です。

環境変数およびexce-path、フレーム、フォントなどの設定はコンソール上のEmacsでは不要なため、上記のinit-mac-gui.elでは`window-system`を使って設定を分岐させています。

コンソール上でEmacsを使わない人は、`window-system`と`system-type`のどちらか一方を使えば十分かもしれません。

### system-name変数 ###
`system-name`変数を使うと、コンピューターのホスト名を取得できるため、コンピューターごとに設定を切り替えられます。
ただし、素の`system-name`では、DNSドメイン名の付いたFQDNしか取得できません。
そこで、ドメイン名を除いたシンプルなホスト名を格納する変数`system-name-simple`を定義しました。

```
(defvar system-name-simple
  (replace-regexp-in-string "\\..*\\'" "" (system-name))
  "The simple host name of the machine Emacs is running on, which is without domain information.")
```

たとえば、ホスト名がtigerのコンピューターだけで有効にしたい設定を次の~/.emacs.d/init-tiger.elファイルに記述したとします。

```
;; フレームの設定
(when (equal window-system 'mac)
  (dolist
      (val
       '(
         (width . 180)
         (height . 55)
         (top . 22)
         (left . 0)
         ))
    (add-to-list 'default-frame-alist val)))
```

ここでは、Emacsアプリの場合にフレームの大きさを設定するようにしています。画面の大きさが異なるMacコンピューターを複数台つかっている場合は、コンピューターごとにフレームの大きさを設定したくなると思います。

この設定は、`system-name-simple`を定義してから次の記述をすることで呼び出すことができます。

```
(when (equal system-name-simple "tiger")
  (load-file "~/.emacs.d/init-tiger.el"))
```

## さいごに ##
`system-type`、`window-system`、`system-name`などの変数を使いこなせば、環境ごとにEmacsの設定を分岐させられます。init.elに記述する設定を、共通部分と特定のシステムやコンピューター向けの部分と分けられるので、保守性や利便性が上がります。

init.elの記述を分けるという点では、Advent Calender2日目の[init.elから設定を追い出してパッケージ化しよう](http://qiita.com/syohex/items/2bec20eb8d29da8761e8)で記載された「私のinit.el長すぎ!!」問題対策と相通ずる部分もあるかとおもいます。

なお、環境ごとに設定を変えるためのEmacsパッケージとして、[init-loader](https://github.com/emacs-jp/init-loader)があるようです。私自身は、`syste-type`などを使う方がシンプルでわかりやすいと思うので、使っていません。

それでは、素敵な年末とEmacsライフを。