perl-completion.elが提供するauto-complete.el用の情報源

設定を見直し中 - すぎゃーんメモから引き続き。
perl-completion.elauto-complete.elを併用してPerlファイルを編集する際、

(add-hook 'cperl-mode-hook
  (lambda ()
    (require 'perl-completion)
    (add-to-list 'ac-sources 'ac-source-perl-completion)))

こんな設定をしておくと、auto-completeの情報源としてperl-completionが定義したac-source-perl-completionを使用するようになり、定義されている予約語や、自分の環境にインストールされているモジュール名などが補完候補に入る。
参考: perl-completion.elとauto-complete.elを連携させる - IMAKADO::BLOG


で、使ってみたのだけどなんか少し動作が詰まるような…。 ちょっと重い?と思って中身を見てみると、

(defvar ac-source-perl-completion
  '((candidates . plcmp-ac-candidates)))

という具合に、ac-source-perl-completionplcmp-ac-candidatesの評価結果を利用している。この中身を見てみると、どうやらplcmp-ac-make-candsを評価して得たwordリストから、ac-target(補完候補を指定するための入力中の文字列、を表す変数のはず)を使って正規表現で先頭一致マッチさせて絞り込んでいるっぽい。
ちなみにac-source-perl-completion-patialという名前で定義されている情報源もあり、こちらはplcmp-ac-candidates-patialという関数の評価結果が使われる。こちらは先頭一致を指定していないので部分一致でも候補として出てくることになる。

ということで毎回すごく頑張って補完候補を絞り込んでいるのだけれど、この作業ってauto-completeの方でやっているはず…
auto-complete.el内で定義されているac-candidates関数は、ac-sourcesから得られた候補それぞれに対し

(try-completion ac-prefix candidates)

のように絞り込みを行っている(ac-targetはac-prefixのaliasなので同じ意味のはず)。だから、perl-completionの方で頑張って絞り込みをしなくても、とりあえず取得出来たwordリストをそのまま情報源として渡してしまって良いのでは…?
と思って

(defvar ac-source-my-perl-completion
  '((candidates . plcmp-ac-make-cands)))
(defun my-cperl-mode-hook ()
  (interactive)
  (perl-completion-mode t)
  (require 'auto-complete)
  (add-to-list 'ac-sources 'ac-source-my-perl-completion))
(add-hook 'cperl-mode-hook 'my-cperl-mode-hook)

というように、plcmp-ac-make-candsをそのままガツンと渡すオレオレac-sourcesを定義してみた。これでもちゃんと予約語やモジュール名がauto-completeによって補完される。

計ってみた

実際のところパフォーマンス的にはどうなのか、

(require 'benchmark)
(defadvice ac-candidates (around ac-benchmark)
  (let ((time (car (benchmark-run ad-do-it))))
    (message "%s" time)))
(ad-activate 'ac-candidates)

と、補完候補を計算するac-candidates関数の評価にかかる時間を計測してみた。比較するのは以下の3つの場合。

  • ac-source-perl-completion
  • ac-source-perl-completion-patial
  • ac-source-my-perl-completion

ac-soucesをそれぞれに設定し、"defined length"と一文字ずつ入力してみた。

;; (setq ac-sources '(ac-source-perl-completion)) の場合
0.0046289999999999994
0.004758
0.004398
0.004568
0.03841
0.004488
0.004573
0.004876999999999999
0.004843999999999999
0.038234
0.0031769999999999997
;; (setq ac-sources '(ac-source-perl-completion-patial)) の場合
0.004902999999999999
0.00436
0.00462
0.004585
0.004079
0.0042959999999999995
0.004928999999999999
0.038235
0.0047079999999999995
0.004647
0.004595999999999999
;; (setq ac-sources '(ac-source-my-perl-completion)) の場合
0.002378
0.002201
0.001972
0.002154 [2 times]
0.001976
0.001997
0.002035
0.0024159999999999997
0.001705
0.002003
0.002016

patialかそうでないかはあまり影響していないけど、やっぱりそのまま渡した方が速くなる。
どうせplcmp-ac-make-candsはそれほど頻繁には変化しないのでcacheしてしまっても良いのかも?
何か意図があってperl-completion側で絞り込みをしているのならアレだけど、特に無いようであればそのまま渡す方法の方がパフォーマンス的には良さそう。微々たる差かもしれないけど一文字一文字の入力に響いてくるので。