次世代anything.elとプラグインをリリース!候補選択は是非anythingを

お待たせしました。メンテナになって初のanything.elをリリースします。オリジナル版を使いやすくするために超強化しました。

[2008/08/26]例を追記しました。

次世代anything.elの開発方針

特徴

  • anything-sources(情報源)に使える属性を増やした
  • ユニットテスト(el-expectations)で堅牢になった
  • 情報源の属性を動的に設定できるようになった(プラグイン
  • anythingを終了せずにアクションを実行(persistent-action)できる
  • 直前のanythingの画面を復活できる(anything-resume)
  • アクションから候補選択へ戻ることができる
  • anythingに省略可能引数が付いてEmacs Lispプログラムへの組み込みが楽にんった
  • *anything*の隣のウィンドウをスクロールできるようになった

- 初期状態の入力を指定できる
- プロンプトを「pattern: 」以外に指定できる
- 最初に選択する候補を指定できる

  • アクションを開かずにデフォルト以外のアクションを指定できるようになった
  • 候補をバッファに置いておく方法(candidates-in-buffer)は高速でおすすめ
  • anything-current-buffer、anything-buffer-file-nameはanythingを起動するときのバッファについての情報
  • 補完入力をanything-completing-read、anything-read-file-nameに置き換えることができるマイナーモード(実験的)
  • 候補をユニットテストできるようになった(anything-test-candidates)
  • actionでanythingを指定できる(ネスト化)
  • delayedを指定しない情報源にも遅延時間を指定できるようになった(anything-input-idle-delay)
  • anything-current-bufferが直前のanything起動から更新されていないかチェックできる(anything-current-buffer-is-modified)
  • anything-sourcesにシンボルのリストを指定できる
  • anythingをC-gで中断したとき、ポイント位置を復元するようになった
  • いくつかのフックを新設

インストール

M-x install-elisp http://www.emacswiki.org/cgi-bin/wiki/download/anything.el
M-x install-elisp http://www.emacswiki.org/cgi-bin/wiki/download/anything-config.el

(require 'anything)
(require 'anything-config)
;; anything-config.elが追随するまでは自分で設定しておく
(define-key anything-map "\C-\M-v" 'anything-scroll-other-window)
(define-key anything-map "\C-\M-y" 'anything-scroll-other-window-down)
(define-key anything-map "\C-z" 'anything-execute-persistent-action)
;; これらを設定すると矢印キーとあわせて右手で操作できる
(define-key anything-map [end] 'anything-scroll-other-window)
(define-key anything-map [home] 'anything-scroll-other-window-down)
(define-key anything-map [next] 'anything-next-page)
(define-key anything-map [prior] 'anything-previous-page)
(define-key anything-map [delete] 'anything-execute-persistent-action)
;;
(define-key global-map 好きなキー 'anything)
(define-key global-map 好きなキー 'anything-resume)
;; anything-c-moccur等のanythingアプリケーションのみ使う場合は
;; anything-sourcesの設定はしなくてもよいが…
(setq anything-sources お好きなように)

設定例は公開しています。
http://www.emacswiki.org/cgi-bin/emacs/RubikitchAnythingConfiguration

候補を完全一致→先頭一致→スペースで区切られた正規表現すべて満たすものの順に表示するプラグインはこちら。

M-x install-elisp http://www.emacswiki.org/cgi-bin/wiki/download/anything-match-plugin.el

migemo化プラグイン化して更新。

M-x install-elisp http://www.emacswiki.org/cgi-bin/wiki/download/anything-migemo.el

GNU GLOBALのanythingインターフェースも同時リリース。

M-x install-elisp http://www.emacswiki.org/cgi-bin/wiki/download/anything-gtags.el

ユーザー視点の新機能

個人的に不満に思っていたところを改善しました。

anything-sourcesがシンボルのリストを取れるようになった

anything情報源はanything-c-source-*の形の変数に代入するのが慣例となっています。今までは

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

のように巨大リストを構成していましたが、次のようにシンボルのリストも取れるようになりました。

(setq anything-sources
      '(anything-c-source-buffers
        anything-c-source-recentf))

こうすることでdescribe-variableしたときにどの情報源がセットされているのかが一目でわかります。おまけに、anything-c-source-*の定義を変更してもanything-sourcesを更新する必要がありません。

anything-input-idle-delayでdelayedではない情報源も遅延させる

今までは重い処理をする情報源には(delayed)をつけることで処理を遅延させてきました。しかし、軽い処理でもanything-sourcesの長さが増えていくにつれて処理が重くなってしまいます。塵も積もれば山となる、というわけで、(delayed)ではない情報源についても遅延時間を設定できるようになりました。
僕は0.2秒に設定しています。キーボード打鍵間より少し長く、なおかつもっさり感がありません。

anything-input-idle-delay秒間入力がないときに*anything*バッファを更新します。さらに (anything-idle-delay - anything-input-idle-delay) 秒後に(delayed)な情報源を処理します。

persistent-action

今までだとアクションを実行したら*anything*バッファが閉じられてしまいます。そこでアクションを実行した後も*anything*バッファを持続させる機能persistent-actionを導入しました。C-zを押すことでpersistent-actionを実行します。

この機能があると、anything-c-source-buffers等でバッファやファイルをチラ見することができます。チラ見が終わったらC-gでanythingをquitすれば元のウィンドウ構成に戻ります。

anything.el を終了せずにアクションを実行する方法 - http://rubikitch.com/に移転しました参照

persistent-actionでバッファを表示した後にスクロールすることができます。通常のバッファ同様C-M-v、C-M-y*1でどうぞ。

anything-resume

アクション実行後に*anything*バッファが閉じられますが、再び同じ候補を表示させるには再度パターンを入力しなければなりませんでした。そこでM-x anything-resumeを実行することで直前の*anything*バッファを復元させることができます。

anything-c-moccurで他のマッチ箇所に移動するときに重宝しています。

デフォルト以外のアクションを選択する

候補を選択すると、デフォルトの(action属性の最初のもの)アクションが実行されます。他のアクションを実行する場合はTabでアクションを選択する必要があります。しかし、実行するアクションがわかりきっている場合は面倒です。そこで、候補選択のところからデフォルトの以外のアクションを実行できるようにしました。
M-x anything-select-2nd-actionで2番目のアクション((nth 1 action)なるアクション)を実行します。同様に anything-select-3rd-action、anything-select-4th-action、 anything-select-nth-action もあります。
anything-mapの空いたキーに割り当てると便利です。

たとえば、行末でC-eを押したときに2番目のアクションを実行するにはこんなコマンドを作成します。行末のC-eは意味がないのでそこを利用したものです。

(defun anything-select-2nd-action-or-end-of-line ()
  (interactive)
  (if (eolp)
      (anything-select-nth-action 1)
    (end-of-line)))
completing-read、read-file-nameのanythingインターフェース

M-x anything-read-string-mode はcompleting-readとread-file-nameをanythingで置き換えるマイナーモードです。ただし、まだ実験段階です。
提供している関数は anything-completing-read と anything-read-file-name です。

(anything-read-file-name "file: " "~" ".emacs")
(anything-read-file-name "file: " "/tmp")
(anything-completing-read "Command: " obarray 'commandp t)
(anything-completing-read "Test: " '(("hoge")("foo")("bar")) nil t)
(anything-completing-read "Test: " '(("hoge")("foo")("bar")) nil nil "f" nil)
(anything-completing-read "Test: " '(("hoge")("foo")("bar")) nil nil "f" nil nil t)
(anything-completing-read "Test: " '(("hoge")("foo")("bar")) nil nil nil nil "nana")
(anything-completing-read "Test: " '("hoge" "foo" "bar"))

開発者向けの情報

おもしろいのはここからです。Emacs Lispが書けるならば、anything.elはしっかり応えてくれます。

新しい属性

情報源をきめ細やかに制御したり、柔軟なプラグインを作成できるように新しいanything-sources属性を用意しました。

「persistent-action」属性には、persistent-actionを実行する関数を指定します。候補を引数とする関数です。省略したときはaction属性の先頭(デフォルトアクション)を実行します。以下の例でC-zを押すとコマンドの説明が出ます。

例(同時にcandidates-in-bufferの例でもある)

(anything
 '(((name . "M-x")
    (init . (lambda ()
              (with-current-buffer (anything-candidate-buffer 'global)
                (loop for sym being the symbols
                      when (commandp sym)
                      do (insert (symbol-name sym) "\n")))))
    (type . command)
    (candidates-in-buffer)
    (persistent-action
     . (lambda (sym) (describe-function (intern sym)))))))

「display-to-real」属性は、*anything*バッファの表示とアクションに渡される候補を別のものにする第2の方法です。今まではcandidatesやcandidate-transformerが (display . real) 形式を出力することで実現していましたが、候補が多くなってくると遅くなってしまいます。アクションに渡す前にその候補だけ変換すればよい場合はdisplay-to-real属性がおすすめです。表示された候補を引数とした関数を指定します。

例(等価ですがぐっと簡潔になりました)

(anything
 '(((name . "TEST")
    (candidates "foo")
    (display-to-real . upcase)
    (action ("identity" . identity)))))

(anything
 '(((name . "TEST")
    (candidates "foo")
    (filtered-candidate-transformer
     . (lambda (c s) (mapcar (lambda (x) (cons x (upcase x))) c)))
    (action ("identity" . identity)))))


「cleanup」属性は、*anything*バッファが閉じられるときに実行する無引数関数です。init属性がコンストラクタならば、cleanup属性はデストラクタと言えるでしょう。不要なバッファを削除するときなどに便利です。

(anything
 '(((name . "test")
    (init . (lambda () (get-buffer-create "erased")))
    (candidates "1")
    (cleanup . (lambda () (kill-buffer "erased"))))))


「candidate-number-limit」属性は、その情報源におけるanything-candidate-number-limitです。anything-candidate-number-limitはグローバルな設定ですが、この属性を指定することでオーバーライドできます。

(let ((anything-candidate-number-limit 5))
  (anything
   '(((name . "default")
      (candidates "1" "2" "3" "4" "5" "6")
      (action . identity))
     ((name . "overrided")
      (candidates "1" "2" "3" "4" "5" "6")
      (candidate-number-limit . 3)
      (action . identity)))))

それらに加えてプラグインで実装されている属性があります。

組み込みプラグイン

元々、情報源にtype属性が指定されていれば、anything-type-attributesからtypeに対応する属性たち(主にaction)を挿入してくれる機能があります。そのおかげで候補がファイル名のときは情報源を定義するたびにファイルを開くなどのアクションを定義せずに(type . file)と書いておくだけですみました。これは、情報源を基本的な属性にコンパイルしていると考えることができます。
この考え方を踏襲し、任意の属性を定義できるようにしたのがプラグインです。anything.el本体では、3種類の属性がプラグインで定義されていて、デフォルトで有効になっています。そのうちひとつは以前からある「type」属性です。

ふたつめは「candidates-in-buffer」属性です。これは、候補の絞り込みを従来の文字列リストをstring-matchで絞り込む方法ではなくて、バッファ内でsearch-forward/re-search-forwardを使って絞り込む方法を提供します。この方法ならば、たくさんの候補を扱うときに速度が大幅に向上します。また、プロセスの出力を扱う場合はcandidates-in-bufferを使う方がコードが簡略になります。candidates-in-buffer属性は、「get-line」属性と「search」属性で細かく制御できます。詳しくはanything.elの新機能「バッファによる候補作成」の予告 - http://rubikitch.com/に移転しましたをどうぞ。↑のpersistent-actionの例もあわせて。

みっつめは「dummy」属性です。入力をそのまま候補にするので、バッファ等を新規作成する情報源を作成するのに便利です。

(anything
 '(((name . "dummy")
    (dummy)
    (action . identity))))
プラグインの作成方法

プラグインは anything-compile-source-functions 変数で指定されているコンパイラ関数を順次呼び出すことで実現しています。「コンパイラ」関数は情報源を引数に取り、コンパイル後の情報源を返す関数です。

プラグインを作成するには、コンパイラ関数を書き、anything-compile-source-functionsにadd-to-listで追加するだけです。具体的な作り方はtype、dummy、candidates-in-bufferの定義を見てみるのが早いでしょう。

anythingの省略可能引数

anything関数は元々無引数でしたが、anythingをEmacs Lispプログラムに組み込むことを考えたら省略可能引数をつけるのが便利と判断しました。

(anything &optional SOURCES INPUT PROMPT RESUME PRESELECT)

SOURCESは上の例にもあるようにanything-sourcesを指定します。もうletバインドする必要はありません。情報源のリスト、シンボルのリスト以外に単一のシンボルも指定できます。例えば、以下のようにすれば、anything-c-source-buffersの動作確認ができます。

(anything 'anything-c-source-buffers)

INPUTは初期状態の入力を指定します。

(anything 'anything-c-source-buffers "any")

PROMPTはプロンプトを指定します。元々は「pattern: 」にハードコーディングされていました。

(anything 'anything-c-source-buffers "any" "Buffer: ")

RESUMEは直前のanythingを復元します。これについてはanything-resume関数を使ってください。

PRESELECTは最初に選択する候補を指定します。候補文字列そのままか正規表現を指定します。

(anything
 '(((name . "test")
    (candidates "1" "2" "3" "4" "5" "6")
    (action . identity)))
 nil nil nil "3")
テスト

anything.elテスト駆動開発を支援します。anything-test-candidates関数が情報源のユニットテストを支援します。

(anything-test-candidates SOURCES &optional (INPUT "")
   (COMPILE-SOURCE-FUNCTIONS anything-compile-source-functions-default))

SOUCESはテスト対象のanything-sources(単独シンボルも含む)、INPUTは初期入力(anything-pattern)、COMPILE-SOURCE-FUNCTIONSは使用するプラグインです。

返り値は以下の形式となります。

  (("source name1" ("candidate1" "candidate2"))
   ("source name2" ("candidate3" "candidate4")))

(anything-test-candidates
 '(((name . "test1")
    (candidates "1" "2" "3" "4" "5" )
    (action . identity))
   ((name . "test2")
    (candidates "6" "7" "8" "9" "10")
    (action . identity))))
まとめ

開発者ならばanything.el冒頭のCommentary、Tips、末尾のユニットテストを読んでみたほうがわかると思います。具体的な使用例は僕の設定をどうぞ。

http://www.emacswiki.org/cgi-bin/emacs/RubikitchAnythingConfiguration

このページは後々追記します。

合言葉は「それanythingでできるよ」!流行らそう。

*1:これはデフォルトではないがw