2012年3月にEmacsの入門書が技術評論社から出版されました。
Emacs実践入門 ~思考を直感的にコード化し、開発を加速する (WEB+DB PRESS plus)
技術評論社
¥ 2,604
インストール方法やファイルの開き方などから始まっていて初心者向けの始まり方になっています。それでは初心者向けなのかというとそうでもなく、中盤から後半はrequireしないと使えないElispを使った拡張方法の紹介になっています。
おそらく、初心者の人は1/3か1/2くらい進んだところで一度脱落するのではないでしょうか。逆に、ある程度知っている人は中盤から後半にかけて興味のある話題が増えていくことでしょう。脱落してしまった人は、しばらく前半の機能でEmacsを使って、慣れてきてから再挑戦するとよいでしょう。
後半の拡張方法の紹介部分では多くの方法を紹介するためか、1つ1つの方法については簡単に紹介する程度にとどまっています。よりつっこんだ使い方までは踏み込んでいません。そのため、すでに最近のEmacs界隈の状況を把握している人やバリバリカスタマイズして使っている人にとっては物足りない内容かもしれません。そうでない人は、こんな方法があるのかと気づくことも多いでしょう。
ということで、今ひとつEmacsを使いこなせていない感のある人は読んでみてはいかがでしょうか。Emacsがより手になじむことになるでしょう。
さて、Emacsが手になじむようになるには自分がEmacsに慣れるだけではなく、Emacsにも自分に歩み寄ってもらうことが近道です。そのためにEmacsの設定をカスタマイズします。
約1年前におすすめEmacs設定を紹介しました。ここで紹介した設定は基本的なものだけに限定していましたが、より細かい設定やrequireしないと使えないElispの設定も増えています。
それでは、1年経ったおすすめEmacs設定を紹介します。
まず、ディレクトリ構成が変わりました。設定ファイルのディレクトリ構成はEmacs実践入門でも提案されていますが、ここではまた違った構成にしています。Emacs実践入門でも「筆者もこの設計がベストだとは思っておらず、より良い配置を模索中です。ぜひもっと優れた設計を考えてみてください。」*1と書かれているので、自分になじむ構成を見つけてください。
.emacs.d |-- init.el ;; 基本的な設定を記述 |-- local.el ;; (カスタマイズ用) |-- config ;; 特定のモードや非標準のElispの設定をこの下に置く | |-- builtins.el ;; 標準Elispの設定 | |-- builtins ;; 標準Elispのうち、設定が多くなるものはこの下に置く | | |-- local.el ;; (カスタマイズ用) | | `-- cc-mode.el ;; (例)標準Elispであるcc-modeの設定 | |-- packages.el ;; 非標準Elispの設定 | |-- packages ;; 非標準Elispのうち、設定が多くなるものはこの下に置く | | |-- local.el ;; (カスタマイズ用) | | `-- sdic.el ;; (例)非標準Elispであるsdicの設定 | `-- el-get ;; el-getの設定はこの下に置く | |-- recipies ;; el-getのレシピはこの下に置く | `-- local-recipies ;; (カスタマイズ用) `-- el-get ;; el-get管理のパッケージをこの下に置く
1年前まではpackage.elという名前の独自のパッケージ管理システムを使っていたのですが、同じ名前のパッケージ管理システムがEmacs 24に標準搭載されることになったため、el-getに乗り換えました。el-getにした理由は元々使っていたパッケージ管理システムと同じことができたからです。
それでは、まず、基本的な設定を説明します。
以前は~/.emacs.d/packagesもパスに入っていましたが、el-get管理になったので除きました。
;;; ロードパスの追加
(setq load-path (append
'("~/.emacs.d")
load-path))
;;; Localeに合わせた環境の設定 (set-locale-environment nil)
C-hの設定をdefine-keyではなくkeyboard-translateを使うようにしました。c-electric-backspaceを明示的にdefine-keyしなくてもよいことに気づいたからです。しかし、キー入力中にC-hを押してもキーバインド一覧が出てこないのは不便なのでdefine-keyに戻すかもしれません。
また、ウィンドウ移動用のキーバインドも追加しました。
;; C-hでバックスペース ;; 2012-03-18 (keyboard-translate ?\C-h ?\C-?) ;; 基本 (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 "M-C-g") 'grep) ; grep (define-key global-map (kbd "C-[ M-C-g") 'goto-line) ; 指定行へ移動 ;; ウィンドウ移動 ;; 2011-02-17 ;; 次のウィンドウへ移動 (define-key global-map (kbd "C-M-n") 'next-multiframe-window) ;; 前のウィンドウへ移動 (define-key global-map (kbd "C-M-p") 'previous-multiframe-window)
便利なのがM-C-gのgrepです。grepにはまだ設定があります。
;; 再帰的にgrep
;; 2011-02-18
(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も使っていましたが、標準の機能で十分なので、もう使っていません。
1年前はshow-trailing-whitespaceを使っていましたが、より多くの空白を視覚化できるwhitespace-modeを使うようにしました。
;; 2011-10-27
;; 空白や長すぎる行を視覚化する。
(require 'whitespace)
;; 1行が80桁を超えたら長すぎると判断する。
(setq whitespace-line-column 80)
(setq whitespace-style '(face ; faceを使って視覚化する。
trailing ; 行末の空白を対象とする。
lines-tail ; 長すぎる行のうち
; whitespace-line-column以降のみを
; 対象とする。
space-before-tab ; タブの前にあるスペースを対象とする。
space-after-tab)) ; タブの後にあるスペースを対象とする。
;; デフォルトで視覚化を有効にする。
(global-whitespace-mode 1)
;;; 現在行を目立たせる (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)
見直したら1年前の設定には抜けていたので追記しました。
ファイルの先頭に#!...があるファイルを保存すると実行権をつけます。
;; 2012-03-15
(add-hook 'after-save-hook
'executable-make-buffer-file-executable-if-script-p)
M-uやM-lだけで十分なら必要ないでしょうが、たまに使いたくなるときがあるのです。
;;; リージョンの大文字小文字変換を有効にする。 ;; C-x C-u -> upcase ;; C-x C-l -> downcase ;; 2011-03-09 (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil)
ウィンドウの上部に現在の関数名を表示します。残念ながら大きい関数を編集しなければいけなくなったときに、今どこにいるかがわかりやすくなって便利です。
;; 2011-03-15 (which-function-mode 1)
ほとんどemacsclientは使いませんが、いつでもつながるようにはしています。
;; emacsclientで接続できるようにする。 ;; 2011-06-14 (server-start)
最後にconfig/以下に置いてある設定ファイルを読み込みます。~/.emacs.d/config/local.elがあればそれも読み込みます。local.elはリポジトリに入っていないファイルです。このおすすめ設定を使う場合はlocal.elを自作してそこでカスタマイズしてください。
;; 標準Elispの設定
(load "config/builtins")
;; 非標準Elispの設定
(load "config/packages")
;; 個別の設定があったら読み込む
;; 2012-02-15
(condition-case err
(load "config/local")
(error))
config/builtins.elには標準Elisp(Emacsに付属しているElisp)の設定を記述します。
diredで"V"を入力するとそのディレクトリで使っているバージョン管理システム用のモードを起動します。1年前のものより賢く検出するようになっています。
;; diredから適切なバージョン管理システムの*-statusを起動
(defun dired-vc-status (&rest args)
(interactive)
(let ((path (find-path-in-parents (dired-current-directory)
'(".svn" ".git"))))
(cond ((null path)
(message "not version controlled."))
((string-match-p "\\.svn$" path)
(svn-status (file-name-directory path)))
((string-match-p "\\.git$" path)
(magit-status (file-name-directory path))))))
(define-key dired-mode-map "V" 'dired-vc-status)
;; directoryの中にbase-names内のパスが含まれていたらその絶対パスを返す。
;; 含まれていなかったらdirectoryの親のディレクトリを再帰的に探す。
;; 2011-03-19
(defun find-path-in-parents (directory base-names)
(or (find-if 'file-exists-p
(mapcar (lambda (base-name)
(concat directory base-name))
base-names))
(if (string= directory "/")
nil
(let ((parent-directory (substring directory 0 -1)))
(find-path-in-parents parent-directory base-names)))))
自動でスペルチェックを実行します。スペルミスの単語は色が変わるのですぐに気づけます。
;; 2011-03-09 (setq-default flyspell-mode t) (setq ispell-dictionary "american")
テキスト編集用のモード共通の設定です。
;; 2012-03-18 ;; text-modeでバッファーを開いたときに行う設定 (add-hook 'text-mode-hook (lambda () ;; 自動で長過ぎる行を分割する (auto-fill-mode 1)))
C言語と同じような構文のプログラミング言語用の設定です。
;; 2012-03-18 ;; c-modeやc++-modeなどcc-modeベースのモード共通の設定 (add-hook 'c-mode-common-hook (lambda () ;; BSDスタイルをベースにする (c-set-style "bsd") ;; スペースでインデントをする (setq indent-tabs-mode nil) ;; インデント幅を2にする (setq c-basic-offset 2) ;; 自動改行(auto-new-line)と ;; 連続する空白の一括削除(hungry-delete)を ;; 有効にする (c-toggle-auto-hungry-state 1) ;; CamelCaseの語でも単語単位に分解して編集する ;; GtkWindow => Gtk Window ;; EmacsFrameClass => Emacs Frame Class ;; NSGraphicsContext => NS Graphics Context (subword-mode 1)))
Elispを編集するときの設定です。
;; 2012-03-18 ;; emacs-lisp-modeでバッファーを開いたときに行う設定 (add-hook 'emacs-lisp-mode-hook (lambda () ;; スペースでインデントをする (setq indent-tabs-mode nil)))
最後に~/.emacs.d/config/buitins/local.elがあればそれもそれも読み込みます。local.elはリポジトリに入っていないファイルです。このおすすめ設定を使う場合はlocal.elを自作してそこでカスタマイズしてください。
;; 個別の設定があったら読み込む
;; 2012-03-18
(condition-case err
(load "config/builtins/local")
(error))
パッケージ管理ステムとして複数のソースからパッケージをインストールできるel-getを使います。el-getがない場合は自動でインストールします。
;; 2012-03-15
(add-to-list 'load-path "~/.emacs.d/el-get/el-get")
(unless (require 'el-get nil t)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.github.com/dimitri/el-get/master/el-get-install.el")
(end-of-buffer)
(eval-print-last-sexp)))
;; レシピ置き場
(add-to-list 'el-get-recipe-path
(concat (file-name-directory load-file-name) "/el-get/recipes"))
;; 追加のレシピ置き場
(add-to-list 'el-get-recipe-path
"~/.emacs.d/config/el-get/local-recipes")
レシピは~/.emacs.d/config/el-get/recipies/に置いています。レシピを追加したい場合は~/.emacs.d/config/el-get/local-recipies/ディレクトリを作ってその下に*.rcpというファイルを作ってください。
grepの結果を直接編集できるようになります。wdiredと合わせてC-c C-cでも編集結果を反映できるようにしています。
;;; *grep*で編集できるようにする
(el-get 'sync '(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でも選択できるようにしています。
;;; 自動補完
(el-get 'sync '(auto-complete))
(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とyank-popの代わりにだけ使っています。imenuの代わりにも使ってみようとしています。
;;; Anything (let ((original-browse-url-browser-function browse-url-browser-function)) (el-get 'sync '(anything)) (require 'anything-config) (anything-set-anything-command-map-prefix-key 'anything-command-map-prefix-key "C-c C-<SPC>") (define-key global-map (kbd "C-x b") 'anything-for-files) (define-key global-map (kbd "C-x g") 'anything-imenu) ; experimental (define-key global-map (kbd "M-y") 'anything-show-kill-ring) (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))
;; 2012-03-19 ;; インストールされていたら有効にする。 (require 'migemo nil t)
Emacsに添付されているruby-modeは古いのでRubyのリポジトリに入っているものを使います。Emacsに添付されているruby-modeでは、C-c C-eでendを挿入することができなかったりします。
;; 2012-03-15 (el-get 'sync '(ruby-mode-trunk))
Rabbitのスライドを編集するためのモードです。
;; 2012-03-16 (el-get 'sync '(rabbit-mode))
C-x C-tで近くにあるrun-test.shやrun-test.rbという名前のファイルを実行するツールです。
;;; テスト実行 (el-get 'sync '(run-test))
最後に~/.emacs.d/config/packages/local.elがあればそれもそれも読み込みます。local.elはリポジトリに入っていないファイルです。このおすすめ設定を使う場合はlocal.elを自作してそこでカスタマイズしてください。
;; 個別の設定があったら読み込む
;; 2012-03-15
(condition-case err
(load "config/packages/local")
(error))
Emacs実践入門と1年経ったおすすめのEmacsの設定を紹介しました。
ここで紹介した内容はGitHubに置いておいたので、興味がある人は試してみてください。使い方はREADMEを参照してください。ここで紹介した内容が難しい場合はEmacs実践入門を読んでみるとよいかもしれません。
Emacs実践入門 ~思考を直感的にコード化し、開発を加速する (WEB+DB PRESS plus)
技術評論社
¥ 2,604
*1 60ページの注2。