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

各言語での利用方法解説

* C/C++ : [company-ironyを使ってemacsでC/C++の補完](http://qiita.com/sune2/items/c040171a0e377e1400f6)
* Python : [company-jediを使ってemacsでpythonの補完](http://qiita.com/sune2/items/017b5fadc43f3c44f299)
* Javascript : [company-ternを使ってemacsでjavascriptの補完](http://qiita.com/sune2/items/e54bb5db129ae73d004b)

# 概要
emacsの補完用パッケージ[company-mode](https://github.com/company-mode/company-mode)の紹介．

![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/81323/19e288a3-9130-97ff-92d5-bd339b3eea73.png)

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

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

# 設定

## 基本

```el
(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)`を消して

```el
(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を挿入

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

```el
(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キーの挙動をいい感じにしたかったので以下のようにした．
まず，候補が１つの場合はそれを選択する．
候補が複数の場合，挿入可能なprefixがあれば挿入し，なければ`company-select-next`するはず．
`company.el`にあった`company--insert-candidate`と`company-complete-common`を少しいじっただけ．

```el
(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は１つだが，上記リストの`(company-dabbrev-code company-gtags company-etags company-keywords)`のように，backendとしてbackendのリストを指定することで，同時に複数のbackendを利用することができる．
また，このような複数指定のbackendのリストには:withキーワードを入れることができる．
:withをいれるときといれないときの正確な動作の違いはよく分かっていないが，少なくとも下で紹介する`company-sort-by-backend-importance`に対して効果を発揮する．

現在選択している補完候補がどのbackendで生成されたものかは，マイナーモード表示部分の，`company-*`の`*`の部分に表示される．
サードパーティのbackendにどのようなものがあるかの一覧は[ここ](https://github.com/company-mode/company-mode/wiki/Third-Party-Packages)にある．

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

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

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


また，それまでどの補完候補を選択したかによってソートする`company-sort-by-statistics`が[company-statistics](https://github.com/company-mode/company-statistics)で提供されている．
これらのtransformerは安定ソートするので，優先度が一致する候補はその順番を保ったままとなる．

自分は，

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

としている．