注: これの更新版である2012年版があります。
他の人がEmacsを使っているのを見ていると、「もっと便利に使えるのに」と、もやっとしたり、「え、その便利な機能ってなに?」と、発見があったりします。だれかに「この設定をすると便利ですよ」と話しやすくするために、今のEmacsのおすすめ設定をここに記しておきます。
ディレクトリ構成
長年漬け込んできたEmacsの設定がそこそこの量になっているので、以下のようなディレクトリ構成にして分類しています。
.emacs.d
|-- init.el ;; 基本的な設定を記述
|-- config ;; 特定のモードや非標準のElispの設定をこの下に置く
| |-- builtins.el ;; 標準Elispの設定
| |-- packages.el ;; 非標準Elispの設定
| `-- packages ;; 非標準Elispのうち、設定が多くなるものはこの下に置く
| `-- sdic.el ;; (例)非標準Elispであるsdicの設定
`-- packages ;; 非標準Elispをこの下に置く
.emacs.d/packages/の下には非標準(Emacsに付属していない)Elispをダウンロードします。これは後述するように自動化しているので、新しい環境でも、.emacs.d/init.elと.emacs.d/config/以下だけあれば同じ環境を構築できます。アップデートしたい場合は単純に.emacs.d/packages/を削除してEmacsを再起動するだけなので手間がかかりません。
init.el: 基本的な設定
それでは、まず、基本的な設定を説明します。
ロードパス
;;; ロードパスの追加
(setq load-path (append
'("~/.emacs.d"
"~/.emacs.d/packages")
load-path))
日本語環境
;;; Localeに合わせた環境の設定
(set-locale-environment nil)
キーバインド
;;; キーバインド
(define-key global-map (kbd "C-h") 'delete-backward-char) ; 削除
(define-key global-map (kbd "M-?") 'help-for-help) ; ヘルプ
(define-key global-map (kbd "C-z") 'undo) ; undo
(define-key global-map (kbd "C-c i") 'indent-region) ; インデント
(define-key global-map (kbd "C-c C-i") 'hippie-expand) ; 補完
(define-key global-map (kbd "C-c ;") 'comment-dwim) ; コメントアウト
(define-key global-map (kbd "C-o") 'toggle-input-method) ; 日本語入力切替
(define-key global-map (kbd "M-C-g") 'grep) ; grep
(define-key global-map (kbd "C-[ M-C-g") 'goto-line) ; 指定行へ移動
便利なのがM-C-gのgrepです。grepにはまだ設定があります。
grep
;;; 再帰的にgrep
(require 'grep)
(setq grep-command-before-query "grep -nH -r -e ")
(defun grep-default-command ()
(if current-prefix-arg
(let ((grep-command-before-target
(concat grep-command-before-query
(shell-quote-argument (grep-tag-default)))))
(cons (if buffer-file-name
(concat grep-command-before-target
" *."
(file-name-extension buffer-file-name))
(concat grep-command-before-target " ."))
(+ (length grep-command-before-target) 1)))
(car grep-command)))
(setq grep-command (cons (concat grep-command-before-query " .")
(+ (length grep-command-before-query) 1)))
-rオプションを追加して常に再帰的にgrepするようにします。grep-findなどを使い分けなくてもすみます。
画像表示
;;; 画像ファイルを表示
(auto-image-file-mode t)
バッファ内で画像ファイルを表示します。
バーを消す
;;; メニューバーを消す
(menu-bar-mode -1)
;;; ツールバーを消す
(tool-bar-mode -1)
カーソル
;;; カーソルの点滅を止める
(blink-cursor-mode 0)
eval
;;; evalした結果を全部表示
(setq eval-expression-print-length nil)
括弧
;;; 対応する括弧を光らせる。
(show-paren-mode 1)
;;; ウィンドウ内に収まらないときだけ括弧内も光らせる。
(setq show-paren-style 'mixed)
昔はmic-paren.elも使っていましたが、標準の機能で十分なので、もう使っていません。
空白
;;; 行末の空白を表示
(setq-default show-trailing-whitespace t)
位置
;;; 現在行を目立たせる
(global-hl-line-mode)
;;; カーソルの位置が何文字目かを表示する
(column-number-mode t)
;;; カーソルの位置が何行目かを表示する
(line-number-mode t)
;;; カーソルの場所を保存する
(require 'saveplace)
(setq-default save-place t)
行
;;; 行の先頭でC-kを一回押すだけで行全体を消去する
(setq kill-whole-line t)
;;; 最終行に必ず一行挿入する
(setq require-final-newline t)
;;; バッファの最後でnewlineで新規行を追加するのを禁止する
(setq next-line-add-newlines nil)
バックアップ
;;; バックアップファイルを作らない
(setq backup-inhibited t)
;;; 終了時にオートセーブファイルを消す
(setq delete-auto-save-files t)
補完
;;; 補完時に大文字小文字を区別しない
(setq completion-ignore-case t)
(setq read-file-name-completion-ignore-case t)
;;; 部分一致の補完機能を使う
;;; p-bでprint-bufferとか
(partial-completion-mode t)
;;; 補完可能なものを随時表示
;;; 少しうるさい
(icomplete-mode 1)
履歴
;;; 履歴数を大きくする
(setq history-length 10000)
;;; ミニバッファの履歴を保存する
(savehist-mode 1)
;;; 最近開いたファイルを保存する数を増やす
(setq recentf-max-saved-items 10000)
圧縮
;;; gzファイルも編集できるようにする
(auto-compression-mode t)
diff
;;; ediffを1ウィンドウで実行
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;;; diffのオプション
(setq diff-switches '("-u" "-p" "-N"))
ディレクトリ
;;; diredを便利にする
(require 'dired-x)
;;; diredから"r"でファイル名をインライン編集する
(require 'wdired)
(define-key dired-mode-map "r" 'wdired-change-to-wdired-mode)
ファイル名をそのまま変更できるのは便利です。
バッファ名
;;; ファイル名が重複していたらディレクトリ名を追加する。
(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward-angle-brackets)
追加の設定をロード
最後にconfig/以下に置いてある設定ファイルを読み込みます。
;;; 標準Elispの設定
(load "config/builtins")
;;; 非標準Elispの設定
(load "config/packages")
config/builtins.el: 標準Elispの設定
config/builtins.elには標準Elisp(Emacsに付属しているElisp)の設定を記述します。まだ整理しきれていないので、1つだけ紹介します。
バージョン管理システム
diredで"V"を入力するとそのディレクトリで使っているバージョン 管理システム用のモードを起動します。
(defun dired-vc-status (&rest args)
(interactive)
(cond ((file-exists-p (concat (dired-current-directory) ".svn"))
(svn-status (dired-current-directory)))
((file-exists-p (concat (dired-current-directory) ".git"))
(magit-status (dired-current-directory)))
(t
(message "version controlled?"))))
(define-key dired-mode-map "V" 'dired-vc-status)
config/packages.el: 非標準Elispの設定
config/packages.elには非標準Elispの設定を記述します。しかし、非標準なので、設定をする前にダウンロードしてくる必要があります。Elispを管理するElispはいくつかあるのですが、以下のような動作をするものがないため、簡単なものを自作しています。
- すでにインストールしていたら何もせずに、なかったらインストールして欲しい。明示的にS式を評価したくない。コメントにインストールS式を残すのではなく、コメントにせずに残したい。
- 非同期ではなく同期でインストールして欲しい。Emacsを起動して、すでにインストールされていなかったらその場でインストールして、インストールが終わったらいつも通り使える状態になって欲しい。インストールしている時間くらい待てるので、がんばって非同期でインストールして、「中途半端に動く状態」だけど「素早く起動」しなくてもよい。多少初回起動時に遅くても、動いたら完全に動く状態になってくれた方がよい。
パッケージ管理システム
config/packages.elの先頭に以下のような簡単なパッケージ管理システムを定義しています。以下の場所にあるElispをインストールできます。
インストールしたパッケージは~/.emacs.d/packages/以下にインストールされます。
(require 'cl)
(defvar package-base-dir "~/.emacs.d/packages")
(defun package-path-basename (path)
(file-name-sans-extension (file-name-nondirectory path)))
(defun package-directory (files)
(concat package-base-dir "/"
(package-path-basename (car files))))
(defun package-run-shell-command (command)
(message (format "running...: %s" command))
(shell-command command))
(defun package-install-from-emacswiki (files)
(shell-command
(format "mkdir -p %s" (package-directory files)))
(package-run-shell-command
(format "wget --directory-prefix %s %s"
(package-directory files)
(mapconcat (lambda (name)
(concat "http://www.emacswiki.org/emacs/download/"
name))
files
" "))))
(defun package-install-from-github (files)
(package-run-shell-command
(format (concat "git clone https://github.com/%s.git %s")
(car files)
(package-directory files))))
(defun package-install-from-repo.or.cz (files)
(package-run-shell-command
(format (concat "git clone git://repo.or.cz/%s.git %s")
(car files)
(package-directory files))))
(defun package-alist-value (alist key default-value)
(if (listp alist)
(let ((alist-item (assoc key alist)))
(if alist-item
(cdr alist-item)
default-value))
default-value))
(defun package-install (type package-spec require-name &optional force)
(let ((files (package-alist-value package-spec 'files
(if (listp package-spec)
package-spec
(list package-spec))))
(base-path (package-alist-value package-spec 'base-path "."))
(additional-paths (package-alist-value package-spec 'additional-paths
nil))
(install-proc (case type
(emacswiki
'package-install-from-emacswiki)
(github
'package-install-from-github)
(repo.or.cz
'package-install-from-repo.or.cz)
(t
(error "unknown package type: <%s>(%s)"
type package)))))
(add-to-list 'load-path
(format "%s/%s"
(package-directory files)
base-path))
(dolist (additional-path additional-paths)
(add-to-list 'load-path (format "%s/%s"
(package-directory files)
additional-path)))
(condition-case err
(require require-name)
(error
(message (format "installing %s..." files))
(funcall install-proc files)))
(require require-name)))
grep-edit: grep結果をインラインで編集
grepの結果を直接編集できるようになります。wdiredと合わせてC-c C-cでも編集結果を反映できるようにしています。
;;; *grep*で編集できるようにする
(package-install 'emacswiki "grep-edit.el" 'grep-edit)
(add-hook 'grep-setup-hook
(lambda ()
(define-key grep-mode-map (kbd "C-c C-c") 'grep-edit-finish-edit)))
Auto Complete: 自動補完
自動で補完候補をだしてくて便利です。補完候補をC-n/C-pでも選択できるようにしています。
;;; 自動補完
(package-install 'github "m2ym/auto-complete" 'auto-complete-config)
(add-to-list 'ac-dictionary-directories
(format "%s/auto-complete/dict" package-base-dir))
(ac-config-default)
(add-hook 'auto-complete-mode-hook
(lambda ()
(define-key ac-completing-map (kbd "C-n") 'ac-next)
(define-key ac-completing-map (kbd "C-p") 'ac-previous)))
Anything
いろいろ便利に使えるらしいAnythingですが、iswitchb-modeの代わりにだけ使っています。isiwtchb-modeの代わりなのでキーバインドはC-x bだけです。
;;; Anything
(let ((original-browse-url-browser-function browse-url-browser-function))
(setq anything-command-map-prefix-key "C-c C-<SPC>")
(package-install 'repo.or.cz '((files . ("anything-config"))
(additional-paths . ("extensions")))
'anything-startup)
(define-key global-map (kbd "C-x b") 'anything-for-files)
(define-key anything-map (kbd "C-z") nil)
(define-key anything-map (kbd "C-l") 'anything-execute-persistent-action)
(define-key anything-map (kbd "C-o") nil)
(define-key anything-map (kbd "C-M-n") 'anything-next-source)
(define-key anything-map (kbd "C-M-p") 'anything-previous-source)
(setq browse-url-browser-function original-browse-url-browser-function))
run-test: テスト実行
C-x C-tで近くにあるrun-test.shやrun-test.rbという名前のファイルを実行するツールです。
;;; テスト実行
(package-install 'github '((files . ("kou/run-test"))
(base-path . "lib"))
'run-test-setting)
まとめ
長年漬け込んできたEmacsの設定を紹介しました。
ここで紹介した内容はGitHubに置いておいたので、興味がある人は試してみてください。