auto-complete.elで自動的に候補を出した状態で補完する(絞り込み・候補選択対応)

テキスト入力中に補完候補を自動的に表示してくれる auto-complete.el をリリースしました — ありえるえりあ

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

たった今auto-complete.elがリリースされた。何かと言うと、自動的に10個の候補がポップアップするdabbrevのようなもの。

ポップアップされたら、C-p/C-nで上下の候補に移動してEnterでその候補を選択する。あるいは、候補が出ているときに続けてタイプするとanything.elのように候補が絞られる。なかなかよさげ。候補選択や絞り込みができる点でanything.elと共通しているが、決定的な違いはわざわざ補完用のコマンドを起動しなくてよいことだ!作者があのMatsuyamaさんだからanything.elに触発されたことはほぼ間違いない。


スクリーンショット
このスクリーンショットの状態で「v」を打つと、とたんに「defvar」のみの候補になるからEnterを押すとdefvarが入力されるわけだ。

デモ動画まで用意されているので見てみよう。百聞は一見に如かずと言うからな、まあ見てみろ。

(require 'auto-complete)
(global-auto-complete-mode t)

で、global-auto-complete-modeが有効になると変数ac-modesに登録されているメジャーモードのみ有効になる。デフォルトの設定はこうなっている。

(defcustom ac-modes
  '(emacs-lisp-mode lisp-interaction-mode
                    c-mode c++-mode java-mode
                    perl-mode cperl-mode python-mode
                    makefile-mode sh-mode fortran-mode f90-mode ada-mode
                    xml-mode sgml-mode)
  "Majo modes `auto-complete-mode' can run on."
  :type '(list symbol)
  :group 'auto-complete)

強いていえば、ウィンドウの下の方だと候補が少ししか出てこなくなるので、その場合は上の方から出てくればいいかなぁ。→そういう場合も全候補を出すようにスクロールするようになった。
それと俺は部分dabbrevを使うからサポートされているとすごい嬉しい。部分dabbrevEmacsWiki: Hippie ExpandのSubstring Expansionが参考になる。実際に俺はそのコードをぱくってhippie-expandで部分dabbrevしている。→やってみた

なかなかオツなものが出てきた。これからの成長が楽しみでならない。さっそくインストールすっか。これだからEmacsはやめられないんだよ。

部分マッチを実現してみた

候補を計算する関数は ac-enum-candidates-function で指定するようになっているので、部分マッチの関数を実装してその変数にセットすればよい。補完の始点を求める関数は ac-find-target-function にセットする。

ac-default-enum-candidatesとhippie-expandのコードを元に適当にやってみた。おかしかったらそのうち修正する予定。

(defvar ac-chars "0-9a-zA-Z\\?!_-")
(defun ac-candidate-substrings-in-buffer ()
  "partial dabbrev for auto-complete."
  (when (> (length ac-target) 1)
    (let ((inhibit-quit nil)            ;for debug
          (i 0)
          candidate
          candidates
          (regexp (concat (regexp-quote ac-target) "[" ac-chars "]*\\b")))
      (save-excursion
        ;; search backward
        (goto-char ac-point)
        (while (and (< i ac-candidate-max)
                    (re-search-backward regexp nil t))
          (skip-chars-backward ac-chars)
          (setq candidate (buffer-substring-no-properties
                           (point)
                           (match-end 0)))
          (when (and (>= (length candidate) 3)
                     (not (member candidate candidates)))
            (setq candidates (cons candidate candidates))
            (setq i (1+ i))))
        ;; search backward
        (goto-char (+ ac-point (length ac-target)))
        (while (and (< i ac-candidate-max)
                    (re-search-forward regexp nil t))
          (goto-char (match-beginning 0))
          (skip-chars-backward ac-chars)
          (setq candidate (buffer-substring-no-properties
                           (point)
                           (match-end 0)))
          (goto-char (match-end 0))
          (when (and (>= (length candidate) 3)
                     (not (member candidate candidates)))
            (setq candidates (cons candidate candidates))
            (setq i (1+ i))))
        (nreverse candidates)))))

(setq ac-source-substrings-in-buffer
      '((candidates  . ac-candidate-substrings-in-buffer)
        (limit . 4)))

[2008/12/30]追記

最新版に対応させた。