Personal tools
You are here: Home ブログ matsuyama 巷で話題の anything.el を使ってみた
Document Actions

巷で話題の anything.el を使ってみた

rubikitch さんのブログで anything.el というのを知った(*)のでここでも紹介します。劣化記事にならないようにがんばります。

(*) http://d.hatena.ne.jp/rubikitch/20070725#1186048100 (とても良いブログです)

anything.el って何?

「open anything」できるようになるらしいのですが、少し抽象的で分かりづらいと思います。簡単に言えば、複数の機能をひとつのインターフェースに統合してしまうということです。例えば、 M-x anything RET emacs と入力すれば、 find-file の候補として ~/.emacs 、 Info の候補として Emacs などが列挙され、さらに絞りこんだり、十字キーで直接選択して実際の機能を利用したりします。

http://dev.ariel-networks.com/Members/matsuyama/images/anything1.png/image

動作原理

antyhing は入力されたパターンと anything-sources に定義されている複数の機能を使ってインクリメンタルに候補を生成します。つまり文字を入力してパターンを更新するたびに新しい候補が出てくるのです。 anything-sources は基本的に名前と候補関数のリストで構成されており、具体的な機能は候補関数として任意に定義させることにより anything の汎用的と拡張性を実現しています。

以下の例はバッファリストの選択機能を実装しています。

機能定義の例 (anything-config.el より抜粋 ):

(defun anything-c-buffer-list ()
  "Return the list of names of buffers with the `anything-buffer'
and hidden buffers filtered out.  The first buffer in the list
will be the last recently used buffer that is not the current
buffer."
  (let ((buffers (remove-if (lambda (name)
                              (or (equal name anything-buffer)
                                  (eq ?\  (aref name 0))))
                            (mapcar 'buffer-name (buffer-list)))))
    (append (cdr buffers) (list (car buffers)))))

(defvar anything-c-source-buffers
  '((name . "Buffers")
    (candidates . anything-c-buffer-list)
    (volatile)
    (type . buffer)))

(setq anything-sources
      (list anything-c-source-buffers))

インストール

以下の URL から anything.elanything-config.el をダウンロードして load-path の通ったところにインストールします。

http://www.emacswiki.org/cgi-bin/wiki/download/anything.el

http://www.emacswiki.org/cgi-bin/wiki/download/anything-config.el

Gentoo の場合は僕の Overlay を利用すれば以下のようにインストールできます(たぶん普通にインストールするほうが楽です)。

% layman -f -o http://gentoo.panicode.com/layman.txt -a panicode
% echo '=app-emacs/anything-9999 **' >> /etc/portage/package.keywords
% echo '=app-emacs/anything-config-9999 **' >> /etc/portage/package.keywords
% emerge anything anything-config

インストールしたら ~/.emacs に以下の設定を書きましょう。

(require 'anything-config)

ちなみに anything.el はコアの実装、 anything-config.el は良く使う機能の定義をまとめたものになっています。バージョンすらない開発途上の elisp なのでやさしく扱ってやってください。僕の環境では問題なかったのですが、知人の環境ではいきなり動かなかったそうです。そういう場合は作者に報告するかバグを潰してあげてください。ちなみに Emacs 22 じゃないと動作しないようです。

設定

anything-config.el には現時点で以下の機能が実装されています。

anything-c-source-buffers
バッファ選択機能を提供します。
anything-c-source-file-name-history
ファイル名履歴から find-file する機能を提供します。
anything-c-source-recentf
recentf を使って file-file する機能を提供します。
anything-c-source-files-in-current-dir
カレントディレクトリにあるファイルを find-file する機能を提供します。
anything-c-source-source-man-pages
man ページを閲覧する機能を提供します。
anything-c-source-info-pages
info ページを閲覧する機能を提供します。
anything-c-source-complex-command-history
コマンド履歴を選択してその SEXP を実行する機能を提供します。
anything-c-source-emacs-commands
Emacs のコマンド (M-x) を呼び出す機能を提供します。
anything-c-source-emacs-functions
Emacs の関数を呼び出す機能を提供します。
anything-c-source-emacs-functions-with-abbrevs
bb => bury-buffer や std => switch-to-buffer のように略語で Emacs の関数を呼び出す機能を提供します。
anything-c-soruce-bookmarks
ブックマークを選択して開く機能を提供します。
anything-c-source-picklist
picklist って何でしょうか、ごめんなさいわかりません。
anything-c-source-imenu
imenu 使ったことないです、ごめんなさい。
anything-c-source-file-cache
file-cache の機能を使って find-file する機能を提供します。
anything-c-source-locate
locate プログラムを使って find-file する機能を提供します。
anything-c-source-tracker-search
tracker-search というプログラムを使ってデスクトトップサーチする機能らしいです。よくわかりません。
anything-c-source-mac-spotlight
Mac の Spotlight を使って find-file する機能を提供します。
anything-c-source-bbdb
BBDB って何でしょうか、ごめんなさいわかりません。
anything-c-source-evaluation-result
候補に使用されるパターンを eval した結果を表示する機能を提供します。
anything-c-source-calculation-result
候補に使用されるパターンを calc-eval した結果を表示する機能を提供します。
anything-c-source-google-suggest
Google Suggest を使った Google 検索機能を提供します。
anything-c-source-jabber-contacts
jabber のコンタクトが表示されるようです。

個人的には anything-c-source-locateanything-c-source-calculation-resultanything-c-source-google-suggest が面白いと思います。特に anything-c-source-calculation-resultanything-c-source-google-sugget は anything の力は find-file のみに限られないことを示す良い例だと思います。

それぞれスクリーンショットを貼ります。

http://dev.ariel-networks.com/Members/matsuyama/images/anything2.png/image
http://dev.ariel-networks.com/Members/matsuyama/images/anything3.png/image

デフォルトでは anything-sources は以下のような定義になっています。

(setq anything-sources
      (list anything-c-source-buffers
            anything-c-source-file-name-history
            anything-c-source-info-pages
            anything-c-source-man-pages
            anything-c-source-locate
            anything-c-source-emacs-commands))

僕は以下のように定義してみました。

(setq anything-sources
      (list anything-c-source-buffers
            anything-c-source-bookmarks
            anything-c-source-file-name-history
            anything-c-source-man-pages
            anything-c-source-info-pages
            anything-c-source-calculation-result
            anything-c-source-locate))

キーバインドは C-x b に割りあてるのが良いと思います。僕は C-x ;iswitchb-buffer に割りあててるので実質 C-x b を使わないのです。

(global-set-key "\C-xb" 'anything)
(global-set-key [?\C-;] 'iswitchb-buffer)
(iswitchb-mode)
(anything-iswitchb-setup)

window-system を利用していない人は C-x ; が使えないので C-x b への割りあては考えたほうがいいかもしれません。

最後に拙作の plocate (*) を anything から使えるように設定してみます(機能自体は locate に似ているので anything-c-source-locate をパクりました)。

(*) http://code.google.com/p/plocate/

(defvar anything-c-source-plocate
  '((name . "Personal Locate")
    (candidates . (lambda ()
                    (apply 'start-process "plocate-process" nil
                           (list "plocate" "-p" "-r" anything-pattern))))
    (type . file)
    (requires-pattern . 3)
    (delayed)))

(setq anything-sources
      (list anything-c-source-buffers
            anything-c-source-bookmarks
            anything-c-source-file-name-history
            anything-c-source-man-pages
            anything-c-source-info-pages
            anything-c-source-calculation-result
            anything-c-source-plocate
            anything-c-source-locate))

ホームディレクトリに DB を構築しておきます。

% cd ~
% plocate -U -e .svn # .svn がうざいので排除しつつ構築

anything-default-directory がホームディレクトリ以下ならホームディレクトリに限定した locate のような動きになります。 locate はシステム全体にやるので早くても結果が返ってくるまで 2, 3 秒かかるのに対して、 plocate の場合は(今回の場合だと)ホームディレクトリ限定なので一瞬で結果が返ってきます。

http://dev.ariel-networks.com/Members/matsuyama/images/anything4.png/image

とりあえず僕はこんな感じの設定で早速使いはじめています。これからいろいろ発見があると思うので引き続きブログに紹介していきたいと思います。

考察

Emacs ができて 20 年以上たっているのに、 anything のような飛躍的な機能改善がぴょこんと出てくるから Emacs はやめられない。今回 anything を使ってみて思った問題点を並べておきます。

  • 候補数を絞るのが難しい(特に locate )
  • 機能ごとの次と前がない
  • 結構重い

多少重複している部分もありますが、おそらく今後の課題は以下に情報を絞るかといかに操作しやすくするかになると思います。また anything にはまだまだ未発見の拡張が隠されているはずです。特筆すべきはアクションは find-file に限らないということです。例えば locate を駆使して #include を挿入する機能を anything で実装したり、などです。僕もいろいろアイデアを出して実装してみたいと思います。ああ幸せ。

追記

とりあえず Occur と Semantic(*) を anything から使えるようにしてみた。 6 時間かかりました。普段から Elisp やってないとダメですね。

(*) http://cedet.sourceforge.net/semantic.shtml

まず Occur の anything 版。

http://dev.ariel-networks.com/Members/matsuyama/images/anything5.png/image

ソースはこんな感じ。

(defvar anything-c-source-occur
  '((name . "Occur")
    (init . (lambda ()
              (setq anything-c-source-occur-current-buffer
                    (current-buffer))))
    (candidates . (lambda ()
                    (setq anything-occur-buf (get-buffer-create "*Anything Occur*"))
                    (with-current-buffer anything-occur-buf
                      (erase-buffer)
                      (let ((count (occur-engine anything-pattern
                                                 (list anything-c-source-occur-current-buffer) anything-occur-buf
                                                 list-matching-lines-default-context-lines nil
                                                 list-matching-lines-buffer-name-face
                                                 nil list-matching-lines-face
                                                 (not (eq occur-excluded-properties t)))))
                        (when (> count 0)
                          (let ((lines (split-string (buffer-string) "\n" t)))
                            (cdr lines)))))))
    (action . (("Goto line" . (lambda (candidate)
                                (goto-line (string-to-number candidate) anything-c-source-occur-current-buffer)))))
    (requires-pattern . 3)
    (volatile)))

次は Semantic を使った移動機能。通常 Speedbar から Semantic を使って関数とかクラスに飛ぶのですが、 Speedbar は邪魔だし操作が煩雑なので anything で使えたほういいでしょう。

http://dev.ariel-networks.com/Members/matsuyama/images/anything6.png/image
http://dev.ariel-networks.com/Members/matsuyama/images/anything7.png/image

ソースはこんな感じ。

(defun anything-c-source-semantic-construct-candidates (tags depth)
  (apply 'append (mapcar '(lambda (tag)
                            (when (and (listp tag)
                                       (or (equal (semantic-tag-type tag) "class")
                                           (eq (semantic-tag-class tag) 'function)))
                              (cons (cons (concat (make-string (* depth 2) ?\s)
                                                  (semantic-format-tag-summarize tag nil t)) tag)
                                    (anything-c-source-semantic-construct-candidates (semantic-tag-components tag) (1+ depth)))))
                         tags)))

(defvar anything-c-source-semantic
  '((name . "Semantic Tags")
    (init . (lambda ()
              (setq anything-c-source-semantic-candidates
                    (anything-c-source-semantic-construct-candidates (semantic-fetch-tags) 0))))
    (candidates . (lambda ()
                    (mapcar 'car anything-c-source-semantic-candidates)))
    (action . (("Goto tag" . (lambda (candidate)
                               (let ((tag (cdr (assoc candidate anything-c-source-semantic-candidates))))
                                 (semantic-go-to-tag tag))))))))

これからもいろいろ実装していきたいと思います。

さらに追記

rubikitch さんからツッコミ (*) をいただいたので修正。どうもありがとうございます。

(*) http://d.hatena.ne.jp/rubikitch/20071009#1191903266

まず機能の次と前がないという話。 anything-next-sourceanything-previous-source がまさにそれでした。以下のように設定しておきました。

(define-key anything-map (kbd "C-M-n") 'anything-next-source)
(define-key anything-map (kbd "C-M-p") 'anything-previous-source)

機能をしぼるのが難しいという話。 rubikitch さんのように locate/updatedb を駆使してホームディレクトリにファイルパスのデータベースを作るのはいい方法だと思います。ていうか updatedb って findoption 渡せるんだ。 slocateupdatedb だとその手のオプション全然うけつけないから plocate なんていうもの作ってしまったよ。 Gentoo だと GNU findutils をインストールしても locate/updatedb がインストールされないので自分で入れないとダメっぽいです。

最後重いという話。重いけど delayed とか anything-sources の量を適切にしてやれば特に問題ないみたい。もちろん今後は大量の anything-sources からも簡単に絞りこめて、かつ速いというのを目指すのだろうけど。

Category(s)
emacs
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/matsuyama/open-anything-emacs/tbping

Re:巷で話題の anything.el を使ってみた

Posted by Anonymous User at 2007-10-23 00:24
分かりやすいチュートリアル有り難うございます。とても役立ちました。

ところで私も「重さ」の点が気になって、delayed を付けたり volatile を外したり
(キャッシュの効果で若干速くなります)、anything-source-filter を設定したり
色々試したんですが、こんな方法に気付きました。

(defadvice anything-check-minibuffer-input (around sit-for activate)
(if (sit-for anything-idle-delay t)
ad-do-it))

つまり、現状だと1文字入力する度に anything バッファの再描画が行われてしまって
いて、これが重さの大きな要因だと思うんです。この変更で、検索文字列を入力し終わっ
てから描画してくれるようになります。どうでしょう?

Re:巷で話題の anything.el を使ってみた

Posted by Anonymous User at 2007-10-24 23:59
たしかに文字入力が軽快になりました。すべてのソースにdelayedがかかった感じになります。早速使います。一応emacs-wikiに書いておきます。

コメントありがとうございます。
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


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