auto-complete から company に移行した

[Emacs Advent Calendar 2020](https://qiita.com/advent-calendar/2020/emacs) の 4 日目の記事です。

12/8： `company-tng` の存在を教えてもらったので追記しました

## なにをやったの

Emacs のリアルタイム補完エンジン二大巨頭として auto-complete, company があると思いますが、私は Emacs を使い始めた頃からずっと auto-complete のお世話になっていました。

しかし最近は company の方が開発が活発になりつつある印象もあるので、思い切って company に切り替えてみました。

移行してみたざっくり感想ですが、いいところとしては：

- やや動作が軽い
- backend, frontend, transformer など補完エンジンの各パーツがプラガブルな設計になっていて良い

いまいちなところとしては：

- auto-complete に慣れていると、細かいところで不親切というか違和感を感じるところはある

と思いました。

後者について、それぞれの気になりポイントと、それに対する私の設定を紹介します。 auto-complete 側の機能を移植するプラグインもいくつか作ってみました。

すでに company ユーザーな方にもちょっと役立つところもあるかもしれません。

## 基本設定
### company-require-match

補完候補の選択を始めると（？）、補完候補にない文字が打てないようになる仕組みがあるっぽいです。いまいちありがたさを感じなかった＆違和感があったので、無効にしました

```emacs-lisp
(setq company-require-match 'never)
```

### その他

その他の設定項目も auto-complete を使用していた時と同じような使用感になるように設定しました。

```emacs-lisp
(setq company-idle-delay 0
      company-minimum-prefix-length 2
      company-selection-wrap-around t
      company-tooltip-align-annotations t)
```

## company-statistics

auto-complete には補完候補を使用頻度に応じていい感じに並べてくれる仕組み (`ac-comphist`) がありましたが、 company にはなかったので相当するプラグインを入れました。

```emacs-lisp
(require 'company-statistics)

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

(company-statistics-mode)
```

## company-dwim

![screencast.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54240/29d6b550-cbf4-9b2e-d99b-7cc6020b3985.gif)

auto-complete のデフォルトの挙動は、

- `TAB` 一回で補完候補の共通部分を展開
- 以降は `TAB` 連打で補完候補を上から順に選択 (`RET` で確定)

となっています。さらに `ac-dwim` が有効になっている場合、最後の「 `RET` で確定」も省略できます (`TAB` をただ連打しているだけでバシャバシャ補完される)。

company の場合、デフォルトの挙動は以下の設定で再現できます。

```emacs-lisp
(global-set-key (kbd "TAB") 'company-complete-common-or-cycle)
(push 'company-preview-common-frontend company-frontends)
```

が、 `ac-dwim` 時の挙動は company には実装されていません。

個人的にこの挙動はマストなので、 company さんに `ac-dwim` っぽく振る舞ってもらうためのプラグインを書きました。

https://github.com/zk-phi/company-dwim

----

追記: company に付属している `company-tng` でも近い挙動を再現できることを教えてもらいました。「company には実装されていません」は調査不足でしたmm ただ、試してはみたものの理想の挙動とは異なっていたので、自分は引き続き `company-dwim` を使用しています (詳細は Readme 参照)

## company-anywhere

![middle.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54240/2355ef17-d23c-befd-8e3b-1ea3de880846.gif)

auto-complete はシンボルの途中部分を補完することもできました。

company にはこの挙動が実装されておらず、カーソルの直後に (空白以外の) 文字がある場合は補完が始まりません。

これもどうしても不便だったので、プラグインを書いてみました。使ってみたい方はこちらからどうぞ。

https://github.com/zk-phi/company-anywhere

## words-in-same-mode-buffers

![smb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54240/23868408-49b4-5853-6607-a808047c78c7.gif)

auto-complete には words-in-same-mode-buffers という source (company でいう backend) があり、これが自分にはかなり使い勝手が良かったです。

これは「現在編集中のバッファ、またはそのバッファと同じメジャーモードになっているバッファ」から補完候補を探してきてくれるものです。 company の capf (`completion-at-point`) のように賢くはありませんが、むしろその素朴な挙動が予測可能な感じで結構好きでした。また fuzzy.el を入れることで、曖昧マッチに対応することもできました (`ac-use-fuzzy`)。

company の場合、 capf に対応しているメジャーモードであれば `completion-styles` をいじることで曖昧マッチには対応することができます。しかし、 capf 非対応のメジャーモード (dabbrev を使う) では曖昧マッチも利用できません。また対応しているメジャーモードでも動作がモタつくことがあるように感じました。

そこでこちらも words-in-same-mode-buffers に相当する感じの company backend を自前で実装してみました。

https://github.com/zk-phi/company-same-mode-buffers

補完候補の集め方は auto-complete の words-in-same-mode-buffers と同じで、あわせて以下のギミックも盛り込んでみました：

- `completion-styles` のように、複数のマッチ戦略を選んでフォールバックできる
- ファイルに補完候補をダンプして、次回起動時いきなり温まった状態から使える
- 補完候補の管理を線形リストではなくパトリシア木にして、補完候補が増えたときのモタつきを減らす

auto-complete の「組み込みのキーワードも words-in-same-mode-buffers の候補もみんないっしょくたに出てくる」あの感じが好きだったので、 `:with` に放り込んで補完候補をかさ増ししてみました。

```emacs-lisp
(setq company-backends
      '(company-files
        (company-css :with company-same-mode-buffers)
        (company-keywords :with company-same-mode-buffers)
        company-same-mode-buffers))
```

`:with` より手前の backend が失敗した場合は下の backend にフォールバックしてくれるみたいなので、そこを意識して設定するとちょっとパフォーマンスがよくなる感じがあります。

## まとめ

そんなこんなで auto-complete の良かったところをそれなりに再現しながら、 company に移行することができました。