他の人が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を再起動するだけなので手間がかかりません。
それでは、まず、基本的な設定を説明します。
;;; ロードパスの追加
(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
(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した結果を全部表示 (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)
;;; 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(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の設定を記述します。しかし、非標準なので、設定をする前にダウンロードしてくる必要があります。Elispを管理するElispはいくつかあるのですが、以下のような動作をするものがないため、簡単なものを自作しています。
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の結果を直接編集できるようになります。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)))
自動で補完候補をだしてくて便利です。補完候補を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ですが、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))
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に置いておいたので、興味がある人は試してみてください。