Personal tools
You are here: Home 原稿・資料 Software Design連載記事「Emacsのトラノマキ」の原稿 Emacsの検索機能を使いこなす(2)(菅原泰樹)
Document Actions

Emacsの検索機能を使いこなす(2)(菅原泰樹)

「Emacsのトラノマキ」 連載第二回 「Emacsの検索機能を使いこなす(2)」 第一回目の原稿(http://dev.ariel-networks.com/articles/emacs/part1)と重複があります。第一回目の原稿が長すぎて分割したためです。

■■■はじめに
前回にひきつづき,今回も検索機能の紹介をしていきます.今回はソースコードブラウズに役立つimenu, etags, gnu-globalを使ったタグジャンプの為の機能と,anythingを使った検索の拡張を紹介します.

■■■imenu -- バッファ内での関数ジャンプ
まずはimenuの紹介です.imenuを使うと そのバッファ内で定義されている関数や変数に簡単にジャンプする事ができます.imenuの利点は後で紹介するetags等と違って特別な準備が必要ない事です.

さて,使ってみましょう.適当なelisp, C, Java等のソースを開いて"M-x imenu"とします.すると以下のようにミニバッファで聞いてくるので,飛びたい先の関数名を入力します.当然タブでの補完もできます.

======================
Index item: lgrep
======================

飛んだあと元の場所に戻りたい場合は"C-u C-SPC"です.実はこの"C-u C-SPC"は何かしてどこかに飛んだあと元の場所に戻ってくるすぐれものコマンドです.一回で戻らない場合は何回か実行すれば大体戻りたい場所に戻ってくれます.この際一緒に覚えてしまいましょう.

■■■etags -- TAGSファイルを使ったソースコードブラウズ
imenuの次はetagsの紹介です.imenuがカレントバッファを対象とした関数ジャンプなら,etagsはファイルをまたがった関数ジャンプを実現します.

etagsではまず外部コマンドを使ってTAGSというインデックスファイルを作る必要があります.

■■Exuberant Ctagsのインストール
まず,TAGSファイルを作る為にExuberant Ctagsをインストールします.Emacs標準で付いてくるetagsコマンドでも問題ないとは思いますが,こっちの方が流行っているようです.長いものには巻かれろです.

オフィシャルサイトは以下のURLです.
http://ctags.sourceforge.net

インストールはオフィシャルサイトからバイナリを落とすなり,aptで入れるなりお好きにどうぞ.Windows用のバイナリもあります.

■■TAGSファイルの作成
さて.まずはTAGSファイルを作らないとetagsが使えません.

例えば,emacs付属のelispのTAGSファイルを作るにはshellから以下のようにします.

======================
$ cd /usr/share/emacs/23.0.60/lisp
$ ctags -R -e
======================

TAGSファイルはビルド時等に作り直すようにしてしまうのがよいでしょう.

これでetagsを使う準備が整いました.

■■etagsを使う
etagsの使い方は簡単です."M-."として,探したい関数名やクラス名を入力するだけです.カーソルが探したい関数名の上にある場合は,その関数をデフォルトで探してくれます.

======================
Find tag: find-file
======================

最初に"M-."としたときは,TAGSファイルの名前を聞かれるので,作ったTAGSファイルを入れてあげましょう.

======================
%Visit tags table (default TAGS): /usr/share/emacs/23.0.60/lisp/TAGS
======================

そうすると,入力した関数名にジャンプする事ができます.もし同じ名前の関数が複数ある場合は"C-u M-."とすると,次の候補を探してくれます.

元の場所に戻りたい場合は"M-*"を押せば戻ってくれます.

■■■gtags -- gnu-global用のインターフェイス
etags, ctagsに似たツールでgnu-globalというものがあります.対応している言語はJava, C, C++, PHPと少ないですが,その言語で開発しているならばさらに強力なソースブラウズ環境が作成できます.

■■gnu-globalのインストール
オフィシャルサイトのURLは以下になります.
http://www.gnu.org/software/global/

インストールはオフィシャルサイトからバイナリをインストールするなり, aptで入れるなりお好きにどうぞ.Windows用のバイナリもあります.

gnu-globalをインストールしたらgtags.elも一緒にインストールしましょう.apt等で入れた場合は勝手にsite-lisp以下に入れてくれると思います.入っていなければ~/.emacs.d/elisp以下あたりに自分で入れてください.

.emacs.elの設定は以下の通りです.

======================
(require 'gtags)
(add-hook 'java-mode-hook (lambda () (gtags-mode 1)))
(add-hook 'c-mode-hook (lambda () (gtags-mode 1)))
(add-hook 'c++-mode-hook (lambda () (gtags-mode 1)))
======================

gtags.elが入ったかは"M-x locate-library"としてからgtags.elと入力してください.入っていれば"Library is file ~/.emacs.d/elisp/gtags.el"のように表示されます.

■■GTAGSファイルの作成
gnu-globalもetagsと同じようにTAGSファイルを作らないといけません.こちらではGTAGSというファイル名になっています.

作るのは簡単です.ソースのルートディレクトリで以下のようにgtagsコマンドを実行するだけです.再帰的にサブディレクトリを辿ってGTAGSファイルを作ってくれます.
======================
> gtags
======================

一度GTAGSファイルを作った後は以下のコマンドを利用する事で,高速に更新する事ができます.
======================
> global -u
======================

■■gtagsを使う
使い方はほとんどetagsと同じです."M-."として探したい関数名やクラス名等を入れるだけです.カーソルが探したい関数名の上にある場合は,その関数をデフォルトで探してくれます.
======================
Find tag: (default Comparator)
======================

同じ名前の関数名やクラス名が複数ある場合は,どれを選ぶかを選択する画面が表示されます.
======================
Comparator 723 .../com/sun/org/apache/xpath/internal/objects/XNodeSet.java abstract class Comparator
Comparator 80 .../java/util/Comparator.java public interface Comparator<T> {
======================

gtagsのetagsより強力な点として,その関数やクラスが使用されている個所を一覧で表示する機能があります."M-x gtags-find-rtag"がそのコマンドです.これを使うと以下のように使用されている個所の一覧を表示する事ができます.
======================
Comparator 109 .../java/text/Collator.java implements java.util.Comparator<Object>, Cloneable
Comparator 3307 .../java/util/Collections.java implements Comparator<Comparable<Object>>, Serializable {
...
======================

元の場所に戻りたいときはetagsと同じように"M-*"で戻れます.

■■■anythingの紹介
さぁ,ここからはanythingを使った検索の拡張について紹介していきます.ここ数年で大分流行っているので知っている方も多いかもしれませんね.

まず,anythingが何かを紹介しましょう.anythingが提供している機能は以下のようなものです.

- Emacsから扱える全てのものをここから開くこと
- 大量のリソースを一覧から簡単に絞りこむ為のインターフェイス
- anythingに新しいソース(後で説明します)を定義する為のフレームワーク

これだと抽象的すぎて分かりづらいですかね.でも使ってみればすぐに分かると思います.

自分自身のことを「open anything」と名乗っているのは伊達じゃありません.本当になんでも開けるし,簡単に探せます.前回紹介した検索用のコマンドもanythingと組み合わせる事でさらに便利に使うことができます.

それではanythingの世界を見ていきましょう.

■■■anythingのインストール
anythingの公式のページはEmacsWikiと作者のrubikichiさんのブログになります.
- EmacsWiki :: http://www.emacswiki.org/emacs/Anything
- rubikichiさんのブログ:: http://d.hatena.ne.jp/rubikitch/

まずはanything.el, anything-config.el, anything-match-plugin.elをインストールします.それぞれの役割は以下のようになっています.
- anything.el :: anythingの基礎部分
- anything-config.el :: 一般的なanytyingのソースの定義
- anything-match-plugin.el :: スペース区切りでand検索を可能にするプラグイン

前回紹介したinstall-elisp(http://www.emacswiki.org/emacs/InstallElisp) を使ってインストールしましょう.
======================
M-x install-elisp-from-emacswiki
Pagename: anything.el
M-x install-elisp-from-emacswiki
Pagename: anything-config.el
M-x install-elisp-from-emacswiki
Pagename: anything-match-plugin.el
======================

■■余談その1(コラム?)(old user向け) install-elispとflim
前回紹介したinstall-elispはwanderlustやemacs-w3mと一緒に使うとうまく動かない事があります.それはwanderlustやemacs-w3mが依存しているflimというパッケージが古い場合や,古いファイルが残っている場合です(筆者は最初はまりました).これはemacs標準で付いてくるurl.elがgnusに付属しているmailcap.elに依存してて、古いflimもmailcap.elを持っている為に起きています.

最近のflimでははmailcap.elはインストールしないようになっているので,"M-x list-load-path-shadows"として不要なmailcap.elを探して削除してしまいましょう.

■■余談その2(コラム?) auto-install
最近はelispのインストーラとしてinstall-elispのかわりにauto-installというものがメジャーになりつつあるようです.anythingのドキュメントのインストール方法もauto-installになりました.auto-installは以下から手に入れる事ができます.
- http://www.emacswiki.org/emacs/AutoInstall
- http://www.emacswiki.org/emacs/auto-install.el

install-elispとの違いは
- 非同期にelispを取ってきてくれる
- auto-install-batchで関連するパッケージをまとめてインストールできる
といったところです.

使い方はほとんどinstall-elispと同じです.単体のelispは"M-x auto-install-from-emacswiki"でインストールできます.auto-installに定義されているパッケージならば"M-x auto-install-batch"でまとめてインストールできます.

Emacsアプリの世界もcpan, gem, easyinstallのようになっていくと良いですね.

■■■anythingの設定
インストールが終わればさっそくanythingを設定していきましょう.

まず以下を.emacs.elに書いておきます.
======================
(require 'anything)
(require 'anything-config)
(require 'anything-match-plugin)
======================

これでanythingを使う準備が整いました.後はanythingから何を検索するかを設定します.anythingでは検索元をソースと呼んでいて,何を検索するかをanything-sourcesという変数に設定します.
まずバッファ,バッファ作成,ファイル履歴,imenuあたりにしておきましょうか.
======================
(setq anything-sources
'(anything-c-source-buffers+
anything-c-source-file-name-history
anything-c-source-buffer-not-found
anything-c-source-imenu
))

;; 自動でimenuのインデックスを作る
(setq imenu-auto-rescan t)
======================

anything-config.elの最初の方に定義済みソースの一覧があるので興味のある方は覗いてみて下さい.

anythingを起動するキーも一緒に設定してしまいましょう.簡単に押せるキーがおすすめです.switch-to-bufferの代わりにもなるので"C-x b"に設定してしまうのもありですね.

======================
(global-set-key (kbd "C-x b") 'anything)
======================

■■■anythingを使う
おもむろに"M-x anything"です.するとバッファの一覧が出てくると思います.
パターンの入力を求められるので,「emacs」等を入力するとその文字で一覧が絞られるのがわかると思います.大体絞り込めたら"C-n", "C-p"で対象を選んで"RET"を押せばそのバッファを選択できます."RET"のかわりに"TAB"を押せばその対象に対して行いたい操作を選ぶ事ができます.

======================
[図1]:img/anything-usage1.png
======================

[図1]を見ると分かるように今回の場合はバッファとファイル履歴をanything-sourcesに登録しているのでバッファだけではなく前に開いた事があるファイルも一緒に出てきています.

複数の条件で絞り込みたい場合、スペースで区切る事でAND検索を行なう事が可能です(anything-match-pluginの機能).

次はimenuを使って関数定義に飛んでみましょう.試しにanything.elを開きます.次に"M-x anything"としてから「sources」と入力します.すると[図2]のように表示されるので好きな関数を選択してジャンプしましょう.

======================
[図2]:img/anything-usage2.png
======================

このように,色々な事への同じ入口の提供,そしてEmacsに分かりやすい選択系のインターフェイスを提供しているのがanythingです.

■■■anything-etags -- anythingのetags用インターフェイス
ここからは色々なanythingのソースを見ていきましょう.

まずはetags用のanything-etagsです.これを使うとEclipseのOpen Typesのようにタグを選ぶことができるようになります.anything-etagsは通常のetagsに比べると以下の利点があります.
- anythingを使ってタグを絞りこめる(当然ですね)
- 今いるファイルからディレクトリを上にさかのぼってTAGSファイルを探してくれる
- 複数のTAGSファイルに対応している

install-elispを使ってインストールします.
======================
M-x install-elisp-from-emacswiki
Pagename: anything-etags.el
======================

.emacs.elには以下のように設定します.
======================
(require 'anything-etags)
(setq anything-sources
'(...
anything-c-source-etags-select))
======================

"M-x anything"とすると[図4]のようになります.
======================
[図4]:anything-etags1
======================

■■■anything-yaetags -- anythingのもう一つのetags用インターフェイス
anything-etagsは便利なのですが,Java等でマッチする候補が多すぎたりと不便な事もあります.そんな時は拙作ですがanything-yaetagsを使います.

anything-yaetagsのanything-etagsとの違いは以下の通りです.
- タグだけを探してくれる(逆に引数名でマッチできない)
- 同じタグが複数あった場合,もう一度anytingで定義を探す
- 一回目がインデックス作成のためにちょっと遅い

install-elispを使ってインストールします.
======================
M-x install-elisp-from-emacswiki
Pagename: anything-yaetags.el
======================

.emacs.elには以下のように設定します.
======================
(require 'anything-yaetags)
(setq anything-sources
'(...
anything-c-source-yaetags-select))
======================

"M-x anything"とすると[図5]のようになります.
======================
[図5]:img/anything-yaetags1.png
======================

■■■anything-gtags -- anythingのgtags用インターフェイス
次はanything-gtagsです.gtagsもanythingと組み合わせるとソースリーディングがさらに楽になるので是非導入してみて下さい.

install-elispを使ってインストールします.
======================
M-x install-elisp-from-emacswiki
Pagename: anything-gtags.el
======================

.emacs.elには以下のように設定します.
======================
(require 'anything-gtags)
(setq anything-sources
'(...
anything-c-source-gtags-select))
======================

"M-x anything"とすると[図6]のようになります.
======================
[図6]:img/anything-gtags1.png
======================

ここでStringを選ぶと[図7]のように実際の定義を探します.
======================
[図7]:img/anything-gtags2.png
======================

■■■locateとanythingを組み合わせる
今度はanythingからlocateを使ってみましょう.anythingとlocateを組み合わせることで深い階層にあるファイルや場所は忘れたけれども名前は覚えているファイルを一発で開く事ができるようになるのでとても便利です.

前回と同様home以下のファイルとプロジェクトごとのファイルをlocateで探す為の設定を紹介します.そのためにhome-locate-make-command-line, plocate-make-command-line関数が必要になるので,前回の記事でこれらの関数を定義していない方は以下のページを見てあらかじめ関数を定義しておいて下さい.
http://dev.ariel-networks.com/Members/sugawara/stuff/sd_emacs/200906_note/

まずはhome以下のファイルをanythingから探す設定です.以下を.emacs.elに追加しましょう.

======================
(defvar anything-c-source-home-locate
'((name . "Home Locate")
(candidates . (lambda ()
(apply 'start-process "anything-home-locate-process" nil
(home-locate-make-command-line anything-pattern "-r"))))
(type . file)
(requires-pattern . 3)
(delayed)))
======================

次はプロジェクトごとのファイルです.以下のように設定します.
======================
(defvar anything-c-source-plocate
'((name . "Project Locate")
(candidates
. (lambda ()
(let ((default-directory
(with-current-buffer anything-current-buffer default-directory)))
(apply 'start-process "anything-plocate-process" nil
(plocate-make-command-line anything-pattern "-r")))))
(type . file)
(requires-pattern . 3)
(delayed)))
======================

そうしたらanything-sourcesにこれらのsourceを追加します.home-locateとplocateの両方を追加する事でproject以下で見つからなかったものをhome-locateの方で探す事ができるようになります.
======================
(setq anything-sources
'(...
anything-c-source-plocate
anything-c-source-home-locate
))
======================

これでanythingからlocateを使う準備が整いました.いままでと同じように"M-x anything"すると[図8]のようにファイルを探せるようになります.すごいですね.
======================
[図8]img/anything-locate1.png
======================

■■■candidates-fileプラグイン -- locateの別解
locateをanythingから使えると便利なのですが,幾つか不便な点もあります.それは,以下の点です.
- サブプロセスを起動するため,一覧に表示されるのに少し時間がかかる
- スペース区切りでの絞り込みができない(anything-match-pluginとサブプロセスの問題)

これを解決する為にanythingの作者のrubikitchさんが以下のエントリーで「candidates-fileプラグイン」を使った解法を紹介しています.
http://d.hatena.ne.jp/rubikitch/20090211/1234349678

candidates-fileプラグインでは以下のような事が行なわれています
- Emacsでファイルリストのバッファを開く
- そのファイルを単純に検索(富豪的!)
- ファイルが更新されたらバッファの内容も更新

ただ検索するだけなんですが,これが速いんです.ファイルリストを作る以外はEmacs内で全て完結しているのでanythingの機能もフルに使えます.ファイルリストの作成に何でも使える所もポイントですね.

興味のある方は覗いてみて下さい.

■■■自分用のソースを定義する
anythingでは自分用のソースを定義する事もできます.ここでは簡単にソースの作り方を説明します.例として複数の選択肢から文字列を入力する為のソースを作ってみます.

anythingのソースは適当な名前の変数に設定された,属性と値のペアのalistです.ソースの名前は慣例的にanything-c-source-* とする事になっているようです.今回作ろうとしているソースは以下のようになります.
======================
(defvar anything-c-source-string-list
'((name . "String List")
(candidates . ("foo" "bar" "baz"))
(action . insert)))
======================

alistの各要素は以下の事を表しています.
- name :: このソースのタイトル.
- candidates :: 一覧される候補.リストか関数を指定する.
- action :: 選択したときに実行される関数.複数指定すると"TAB"を押したときにactionを選択できる.

これをanything-sourcesに設定して"M-x anything"とすると[図3] のようになります.
======================
[図3]:img/anything-c-source-string-list.png
======================

先程はcandidatesに固定のリストを使いましたが,関数を使うことで動的に作成する事も可能です.今度はカレントディレクトリ内にあるファイルを一覧するソースを作ってみます(実はanything-c-source-files-in-current-dirの改変です).
======================
(defvar anything-c-source-directory-files
'((name . "Directory Files")
(candidates
. (lambda ()
(with-current-buffer anything-current-buffer
(directory-files default-directory))))
(type . file)))
======================

このようにcandidatesに関数を登録すると動的に一覧を作る事ができます.今回のソースにはanything-current-bufferという変数とtypeというalistの要素が出てきました.これらは以下を表しています.

- anything-current-buffer :: anythingを実行した元のバッファが保存されている変数.
- type :: actionに指定する関数群を定義した名前.どのようなtypeがあるかはanything-type-attributesという変数をdescribe-variableすると見る事ができる.

ソースに使える要素のうち,代表的なものを[表1]に簡単にまとめておきます.詳細はanything-sourcesのdocstringやanything-config.elでの使われ方を見て下さい.
======================
[表1]
| 要素名 | 説明 |
| name | ソースのタイトル |
| candidates | 一覧される候補 |
| action | 選択したときに実行される関数 |
| type | actionに指定する関数群を定義した名前 |
| init | ソースの初期化 |
| requires-pattern | 候補を表示するのに必要な文字数 |
| candidates-in-buffer | バッファを使って大量の候補を高速に絞りこむ. |
| | initでanything-candidate-buffer関数を使って |
| | バッファを準備する必要がある |

======================

* 最後に
今回はタグジャンプを行なうための機能と,anythingの機能を紹介しました.
ソースコードブラウズに便利なelispはまだ他にも色々あります.筆者は使っていませんが,ECB(http://ecb.sourceforge.net/)やebrowse(Emacs標準機能)もなかなか強力そうです.

anythingは本当にすごいです.anythingを使いはじめてから,知っているファイルを探すときはほとんどfind-fileしなくなってしまいました.選択・一覧系のelispを普通の補完ではなくanythingで選択するようにもしています.といっても普通の補完も便利ですけどね.適材適所です.

筆者はanything用の便利そうな機能を作ったら適宜EmacsWikiに上げるようにしています.みなさんも良いものを作ったら是非EmacsWikiに上げるようにして下さい.世界中の人がよろこびます.


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.