2023年4月03日
companyはauto-completeの次に出てきたEmacsのデファクトスタンダードとなった入力補完パッケージです。これを入れないでコーディングするのは考えられないほど強力なパッケージです。companyは基本設定だけでもかなり便利に使えますが、ここで紹介しているパッケージと設定を加えれば、より便利になるので、ぜひ試してみてください。
こちらの記事を大変参考にさせていただきました。
最初に完成したcompanyの設定コードを記述しておきます。
(use-package company
:ensure t
:after company-statistics
:bind (("M-<tab>" . company-complete) ;; Tabで自動補完を起動する
:map company-active-map
;; C-n, C-pで補完候補を次/前の候補を選択
("M-n" . nil) ;; M-nで次の候補への移動をキャンセル
("M-p" . nil) ;; M-pでの前の候補への移動をキャンセル
("C-n" . company-select-next) ;; 次の補完候補を選択
("C-p" . company-select-previous);; 前の補完候補を選択
("C-s" . company-filter-candidates) ;; C-sで絞り込む
:map company-search-map
;; 検索候補の移動をC-nとC-pで移動する
("C-n" . company-select-next)
("C-p" . company-select-previous))
:init
;; 全バッファで有効にする
(global-company-mode)
:config
(define-key emacs-lisp-mode-map (kbd "C-M-i") nil) ;; CUI版のためにemacs-lisp-modeでバインドされるC-M-iをアンバインド
(global-set-key (kbd "C-M-i") 'company-complete) ;; CUI版ではM-<tab>はC-M-iに変換されるのでそれを利用
(setq completion-ignore-case t)
(setq company-idle-delay 0) ;; 待ち時間を0秒にする
(setq company-minimum-prefix-length 2) ;; 補完できそうな文字が2文字以上入力されたら候補を表示
(setq company-selection-wrap-around t) ;; 候補の一番下でさらに下に行こうとすると一番上に戻る
(setq company-transformers '(company-sort-by-occurrence company-sort-by-backend-importance))) ;; 利用頻度が高いものを候補の上に表示する
(use-package company-statistics
:ensure t
:init
(company-statistics-mode))
;; auto-completeに近い挙動で候補の絞り込みができる
(use-package company-dwim
:straight '(company-dwim
:type git
:host github
:repo "zk-phi/company-dwim")
:ensure t
:init
(define-key company-active-map (kbd "TAB") 'company-dwim)
(setq company-frontends
'(company-pseudo-tooltip-unless-just-one-frontend
company-dwim-frontend
company-echo-metadata-frontend)))
;; カーソルの位置がどこであってもcompanyを起動できる
(use-package company-anywhere
:straight '(company-anywhere
:type git
:host github
:repo "zk-phi/company-anywhere")
:ensure t)
;; プログラムの関数、変数のキーワード補完を強化
(use-package company-same-mode-buffers
:straight '(company-same-mode-buffers
:type git
:host github
:repo "zk-phi/company-same-mode-buffers")
:after company
:ensure t
:init
(require 'company-same-mode-buffers)
(company-same-mode-buffers-initialize)
;;
:config
(setq company-backends
'((company-capf :with company-same-mode-buffers)
(company-dabbrev-code :with company-same-mode-buffers)
company-keywords
company-files
company-dabbrev)))
companyのインストールと基本設定
companyの基本バインドから説明します。companyのデフォルトバインドでは補完候補が表示さた時の移動が
M-n or M-p
で指がきついので、その設定を無効にして、代わりにC-n or C-p
で移動できるようにしています。:config
にはより使いやすくするための変更が記述されています。
company-idle-delay
は補完候補が表示されるまでの遅延です。デフォルトは0.2秒で遅く感じたので0秒にしています。company-minimum-prefix-length
は候補が表示されるまでの最低入力文字数です。デフォルトでは3文字以上で、これもやや遅く感じたので、2文字から候補が表示されるようにしています。company-selection-wrap-around
は候補を移動して、一番下、または一番上まで来たら候補をループできるようにしています。表示順を使用頻度で並び替える
companyの
company-transformers
は表示順を管理しています。デフォルトではcompany-sort-by-occurrence
が設定されており、基本は50音順で表示され、使用頻度が高いものは優先して表示されます。company-statistics
はサードパーティ製の表示順をスマートにするパッケージです。で、ここがトリッキーなところです。順当にcompany-statistics
を使う場合は、インストールして、company-transformers
の並び順を(company-sort-by-statistics company-sort-by-backend-importance)
に変更します。ですが
company-sort-by-statistics
を指定すると、思ったような順番に候補を表示してくれなかったので、あえてデフォルトのままcompany-transformers
を使っています。じゃあcompany-statistics
いらないじゃんと思いきや、これがないとそれはそれで候補の順番が異なってしまいます。実際に使ってみましょう。例えば、このような3つの関数があったとします。
(defun show-file-name ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name)))
(defun show-file-name2 ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name)))
(defun show-file-name3 ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name)))
直近で記述した関数が
show-file-name3
なら候補の一番上に表示されます。フロントの表示に関する設定
company-frontends
関数はcompanyのUI挙動を担います。
デフォルトでは(company-pseudo-tooltip-unless-just-one-frontend company-preview-if-just-one-frontend company-echo-metadata-frontend)
が設定されています。これらの挙動をから解説します。company-pseudo-tooltip-unless-just-one-fronten
は入力候補がある場合、ツールチップを表示する宣言です。これが宣言されていないと、ツールチップが表示されません。company-preview-if-just-one-frontend
はもしも、入力候補が1つしかない場合でもその候補をエディタ上で表示するという宣言です。例えば、入力補完を使うわずに
(file-attribute-
まで入力してa
とタイプすると、それにマッチする唯一の候補がエディタ上に表示されます。company-echo-metadata-frontend
は候補で選択している関数や変数にメタデータがあれば、それをエコーエリアに表示します。候補の選択を変更する
company-frontends
を編集することで、タブによる候補絞り込みの挙動を変更します。
companyの候補選択はやたらと、文字入力による絞り込みを推してきます。
一方で昔よく使われていたauto-complete
はタブでうまい具合に目的の単語を絞り込むことができていました。company-dwim
はその文化を踏襲しています。このパッケージを作った
zk-phi
の記事にもある通り、companyにもタブ絞り込みのcompany-tng-mode
があります。company-tng-mode
は挙動がかなり微妙なので、不要かと思いますが、そちら説明をした上でcompany-dwim
がどれほど素晴らしいか説明します。company-tng-mode
公式リポジトリはこちらになります。
company-tng-mode
はcompanyを入れた時点で入っています。試しに使うためにM-x company-tng-mode
で有効にします。例えば、あやふやな記憶の中で
coding-system-lessp
とcoding-system-list
の2つがあり、その内のcoding-system-lessp
を入力したいとします。(cod
とまで打ち込み、候補を見てみます。50音順では
l
は後ろの方なので、最初の候補一覧には表示されていません。ここでタブを押すと、候補の一番上
coding-system-aliases
に選択が当たります。company-tng-mode
は一度でもタブを押したら、あとは候補をタブで連打して移動する方法でしか絞り込めません。理想的には共通する
coding-system-
までが補完されて、あとはl
をタイプするだけで残りの2つに絞り込める方が良いですよね。もう1つ微妙なのは、候補を選択するためにエンターを押すと、改行されてしまう点です。
以上が
company-tng-mode
の入力補完機能です。結局使わないので、解説は不要かと思いましたが、何がダメなのかを知っておくのは良いと思うので載せておきました。company-dwim
同じように
coding-system-lessp
を入力したいとしましょう。(cod
とまで打ち込み、候補を見てみます。共通した候補の
(coding-system-
まで、タブを一回押すことで補完してもらいます。l
をタイプすると、候補が2つに絞られます。そのままエンターを押せば入力補完されます。改行もされません。
company-anywhereでどこでも補完する
company-anywhere
は同じくzk-phi
さんが作ったcompanyの補完機能を強化するパッケージです。companyは補完が始まる条件として、カーソルの直後にスペースがないと発動しません。それをどこであってもM-<tab>
で補完を発動させます。設定は特に必要ないです。同一シンボルを補完
companyの補完候補を探すアルゴリズムは
company-backends
で指定されています。列挙された上からマッチするか試され、マッチした場合は候補リストが表示されます。なので定義する項目と順番が重要になります。デフォルトの設定
まずはデフォルトのbackendsを見てみましょう。
(company-bbdb
company-semantic
company-cmake
company-capf
company-clang
company-files
(company-dabbrev-code company-gtags company-etags company-keywords)
company-oddmuse
company-dabbrev)
よく使われるものから説明していきます。
company-capf
は公式サイトによれば、lisp、css、nxml系の入力をサポートするものです。elispで設定を作っているときは欠かせません。逆にlisp以外のプログラム言語の補完はやってくれないので、ライトユーザーはそこまで恩恵がありません。company-files
は文字列でディレクトリのパスが記述されると、そのファイルから見たファイル指定への補完が走ります。(company-dabbrev-code company-gtags company-etags company-keywords)
はリストでまとめられています。このように書くと、リスト内のbackendエンジン全てで検証されてマッチするものがあるかどうか判断され、どれかにマッチした場合は結果が返されます。company-dabbrev-code
はプログラミング系で起動してdabbrevと近い挙動で補完してくれます。company-dabbrev
はキャメルケースやスネークケースを考慮しませんが、こちらはその辺りを考慮して補完してくれます。company-keywords
は各プログラム言語で使う予約語等を補完してくれます。company-dabbrev
はdabbrevのキーワードにマッチするものを補完してくれます。company-gtags
はサードパーティ製のgtags-mode
で補完されるエンジンです。それをあえて使っていない限りは使いません。company-etags
もgtags
と同じ感じなのかなぁ〜?検索してもよくわかりません。company-semantic
、company-cmake
、company-clang
はそれぞれC言語系の入力補完をサポートしてくれます。company-bbdb
はbbdb
という電子メールのアドレス、電話番号などのアドレス帳を提供する機能を補完します。company-oddmuse
はoddmuse
というemacs関連のwikiを編集するメジャーモードで、wikiの書き方を補完してくれるっぽいです。キーワード補完を強化
company-same-mode-buffers
は同一のメジャーモードで開いているバッファ内からキーワードを探索して補完してくれます。詳しくは作者のこの部分を読むとどういったことができるかわかります。compan-keywordsと似ていますが、より強化されているので、こちらを優先的に使えるように設定しています。同時にあまり使うことがなさそうなbackendsを取り除いています。
(setq company-backends
'((company-capf :with company-same-mode-buffers)
(company-dabbrev-code :with company-same-mode-buffers)
company-keywords
company-files
company-dabbrev)))
まとめ
companyの細かい記述と使いやすい設定を紹介しました。
もしも、今後より使いやすい何かが見つかった場合はそれも加えて紹介したいと思います。
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。