Emacs

emacsの補完用パッケージcompany-mode

More than 3 years have passed since last update.

各言語での利用方法解説

概要

emacsの補完用パッケージcompany-modeの紹介.

screenshot.png

auto-completeとの比較

emacsの補完といえばauto-completeがある.
auto-completeとcompany-modeの違いは,githubのissueでまとめられている.
company-modeは拡張をシンプルに書けるところが魅力らしい.
るびきち氏の紹介ページによると,メンテナが数年前に引き継がれたらしい.
githubを見ると今も開発が活発に行われていることが分かる.
個人的にはcompany-modeの方が独自設定の仕方が分かりやすい印象を受けた(というかauto-completeの独自設定をしたことがない).
現状,auto-completeに比べて日本語の情報がほとんどないので,これから盛り上がってくれることを期待している.

インストール

melpaにあるのでM-x list-packagesからインストール可能.

設定

基本

(require 'company)
(global-company-mode) ; 全バッファで有効にする 
(setq company-idle-delay 0) ; デフォルトは0.5
(setq company-minimum-prefix-length 2) ; デフォルトは4
(setq company-selection-wrap-around t) ; 候補の一番下でさらに下に行こうとすると一番上に戻る

特定のmodeだけでcompany-modeを有効にしたいときは,(global-company-mode)を消して

(add-hook 'python-mode-hook 'company-mode)

等でOK.

キー

候補表示中における主なキー設定

  • M-n 次の候補選択
  • M-p 前の候補選択
  • C-g 候補選択中止
  • RET 候補選択
  • F1, C-h docを別バッファに表示
  • C-w 定義場所を表示
  • C-s 候補検索
  • C-M-s 候補フィルタリング
  • [tab] 共通するprefixを挿入

自分は以下のように修正している.

(define-key company-active-map (kbd "M-n") nil)
(define-key company-active-map (kbd "M-p") nil)
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "C-h") nil)

さらに,TABキーの挙動をいい感じにしたかったので以下のようにした.
まず,候補が1つの場合はそれを選択する.
候補が複数の場合,挿入可能なprefixがあれば挿入し,なければcompany-select-nextするはず.
company.elにあったcompany--insert-candidatecompany-complete-commonを少しいじっただけ.

(defun company--insert-candidate2 (candidate)
  (when (> (length candidate) 0)
    (setq candidate (substring-no-properties candidate))
    (if (eq (company-call-backend 'ignore-case) 'keep-prefix)
        (insert (company-strip-prefix candidate))
      (if (equal company-prefix candidate)
          (company-select-next)
          (delete-region (- (point) (length company-prefix)) (point))
        (insert candidate))
      )))

(defun company-complete-common2 ()
  (interactive)
  (when (company-manual-begin)
    (if (and (not (cdr company-candidates))
             (equal company-common (car company-candidates)))
        (company-complete-selection)
      (company--insert-candidate2 company-common))))

(define-key company-active-map [tab] 'company-complete-common2)
(define-key company-active-map [backtab] 'company-select-previous) ; おまけ

補完の仕組み(推測)

  1. company-backendsで補完候補リストを取得
  2. company-transformersで候補リストを変形(ソートなど)
  3. company-frontendsで候補リストを表示

company-frontendsについては具体的な動作を調べてないので,1と2についてだけ項を作って紹介する.

company-backends

company-backendsはcompany-modeで用いる補完エンジンのリストである.
これにbackendを追加することにより,新たな補完エンジンでの補完を可能にする.
デフォルトでは,

(company-bbdb company-nxml company-css company-eclim company-semantic company-clang company-xcode company-cmake company-capf (company-dabbrev-code company-gtags company-etags company-keywords) company-oddmuse company-files company-dabbrev)

となっている.
このリストに含まれるbackendを前から試していき,その状況(?)で補完に使えそう(?)なbackendが見つかったらそのbackendから補完候補を取得するという仕組みになっている.
何やらよく分からないbackendも含まれているが,デフォルトでelispやファイルパスやCSSなどの補完ができる.

基本的に同時に利用されるbackendは1つだが,上記リストの(company-dabbrev-code company-gtags company-etags company-keywords)のように,backendとしてbackendのリストを指定することで,同時に複数のbackendを利用することができる.
また,このような複数指定のbackendのリストには:withキーワードを入れることができる.
:withをいれるときといれないときの正確な動作の違いはよく分かっていないが,少なくとも下で紹介するcompany-sort-by-backend-importanceに対して効果を発揮する.

現在選択している補完候補がどのbackendで生成されたものかは,マイナーモード表示部分の,company-**の部分に表示される.
サードパーティのbackendにどのようなものがあるかの一覧はここにある.

company-transformers

補完候補のリストに対して,company-transformersに含まれるtransformerを前から適用していくことにより,補完候補の順番を変える.
デフォルトではnilであり,このとき辞書順になる.
標準のcompany-modeには,company-sort-by-occurrencecompany-sort-by-backend-importanceが用意されている.

  • company-sort-by-occurrence
    現在のバッファの現在見えている部分の中で各候補を検索してその結果からうまいことランク付けしてソートする.

  • company-sort-by-backend-importance
    backendがgroup(リスト)のとき,:withキーワードの前にあるbackendから生成されたものが前に並び,後ろにあるbackendから生成されたものが後ろに並ぶ.

また,それまでどの補完候補を選択したかによってソートするcompany-sort-by-statisticscompany-statisticsで提供されている.
これらのtransformerは安定ソートするので,優先度が一致する候補はその順番を保ったままとなる.

自分は,

(setq company-transformers '(company-sort-by-statistics company-sort-by-backend-importance))

としている.