背景
【2023年1月7日】大幅に更新しました。
こんばんは。Emacs歴2年の初心者です。
これまで入力補完にはcompanyを使用していましたが、corfu+capeが想像以上に良かったのと、設定に関する日本語記事があまりなかったので書いてみました。
corfuに興味のある方の参考になれば幸いです。
前提条件
corfuはEmacs27以上が必須になります。
また、CUI版Emacsでは使用できません。 corfu-terminalを利用するとCUI版でも使用できます。
セットアップ
今回設定するパッケージは下記のとおりです。
- corfu
- cape
- orderless
- prescient
- kind-icon
-
corfu-doccorfu
本体に統合されました。(corfu-popupinfo
) - yasnippet
- tempel
- lsp-mode
corfu
まずは基本となるcorfuを設定します。
VSCodeのようにTABで補完し、RETはそのまま改行するように設定しています。
https://github.com/minad/corfu#tab-only-completion
(use-package corfu
:custom ((corfu-auto t)
(corfu-auto-delay 0)
(corfu-auto-prefix 1)
(corfu-cycle t)
(corfu-on-exact-match nil)
(tab-always-indent 'complete))
:bind (nil
:map corfu-map
("TAB" . corfu-insert)
("<tab>" . corfu-insert)
("RET" . nil)
("<return>" . nil))
:init
(global-corfu-mode +1)
:config
;; java-mode などの一部のモードではタブに `c-indent-line-or-region` が割り当てられているので、
;; 補完が出るように `indent-for-tab-command` に置き換える
(defun my/corfu-remap-tab-command ()
(global-set-key [remap c-indent-line-or-region] #'indent-for-tab-command))
(add-hook 'java-mode-hook #'my/corfu-remap-tab-command)
;; ミニバッファー上でverticoによる補完が行われない場合、corfuの補完が出るようにします。
;; https://github.com/minad/corfu#completing-in-the-minibuffer
(defun corfu-enable-always-in-minibuffer ()
"Enable Corfu in the minibuffer if Vertico/Mct are not active."
(unless (or (bound-and-true-p mct--active)
(bound-and-true-p vertico--input))
;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
(setq-local corfu-echo-delay nil ;; Disable automatic echo and popup
corfu-popupinfo-delay nil)
(corfu-mode 1)))
(add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)
;; lsp-modeでcorfuが起動するように設定する
(with-eval-after-load 'lsp-mode
(setq lsp-completion-provider :none)))
cape
次にcapeを設定します。
corfuだけでも使用できますが、completion-at-point
を自分好みにカスタマイズしたり、様々なcompletion-at-point
を追加することができるようになります。今回はtempel
やtabnine
等も組み合わせています。
(use-package tabnine
:hook ((prog-mode . tabnine-mode)
(text-mode . tabnine-mode)
(kill-emacs . tabnine-kill-process))
:bind (:map tabnine-completion-map
("TAB" . nil)
("<tab>" . nil))
:init
(tabnine-start-process)
(global-tabnine-mode +1))
(use-package cape
:hook (((prog-mode
text-mode
conf-mode
eglot-managed-mode
lsp-completion-mode) . my/set-super-capf))
:config
(setq cape-dabbrev-check-other-buffers nil)
(defun my/set-super-capf (&optional arg)
(setq-local completion-at-point-functions
(list (cape-capf-noninterruptible
(cape-capf-buster
(cape-capf-properties
(cape-capf-super
(if arg
arg
(car completion-at-point-functions))
#'tempel-complete
#'tabnine-completion-at-point
#'cape-dabbrev
#'cape-file)
:sort t
:exclusive 'no))))))
(add-to-list 'completion-at-point-functions #'tempel-complete)
(add-to-list 'completion-at-point-functions #'tabnine-completion-at-point)
(add-to-list 'completion-at-point-functions #'cape-file t)
(add-to-list 'completion-at-point-functions #'cape-tex t)
(add-to-list 'completion-at-point-functions #'cape-dabbrev t)
(add-to-list 'completion-at-point-functions #'cape-keyword t))
-
completion-at-point-functions
は複数のcompletion-at-pointが格納でき、格納された順番に評価されます。 -
cape-super-capf
は複数のcompletion-at-pointを一つにまとめることができます。 -
cape-wrap-buster
で常に最新の候補を表示するようにします。(https://github.com/minad/corfu/wiki#continuously-update-the-candidates)
orderless
次にorderlessを設定します。
Emacs標準の補完スタイルのflex
でも構いませんが、orderless
のほうが絞り込み速度が早く、後述のprescient
と組み合わせることで使い勝手も向上します。
より高度な設定はこちらで紹介しています。
(use-package orderless
:init
(setq completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides nil)
:config
;; migemoでローマ字検索を有効にする
(with-eval-after-load 'migemo
(defun orderless-migemo (component)
(let ((pattern (downcase (migemo-get-pattern component))))
(condition-case nil
(progn (string-match-p pattern "") pattern)
(invalid-regexp nil))))
(add-to-list 'orderless-matching-styles 'orderless-migemo))
;; corfuはorderless-flexで絞り込む
(with-eval-after-load 'corfu
(add-hook 'corfu-mode-hook
(lambda ()
(setq-local orderless-matching-styles '(orderless-flex))))))
prescient
presicent
は候補を履歴・頻度・長さの順に並び替えてくれるパッケージで、従来はselectrum
やivy
、company
のパッケージしか対応していませんでしたが、最近vertico
やcorfu
も対応しました。
prescient
をcompletion-styles
にそのまま設定することもできますが、orderless
の方がパフォーマンスが良いので、組み合わせています。
【余談】hotfuzz
の作者がcompletion-styles
のパフォーマンス測定用のリポジトリを公開してくれているので、興味がある方はお試しください。
(use-package prescient
:config
(setq prescient-aggressive-file-save t)
(prescient-persist-mode +1))
(use-package corfu-prescient
:after corfu
:config
(with-eval-after-load 'orderless
(setq corfu-prescient-enable-filtering nil))
(corfu-prescient-mode +1))
kind-icon
corfuにアイコンをつけるパッケージです。
(use-package kind-icon
:after corfu
:custom (kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
corfu-doc corfu-popupinfo
補完候補の隣に説明が表示されるようになります。
corfu
本体に統合され、extensions
ディレクトリに格納されています。
straight
やelpaca
を使用している場合はcorfu
の宣言箇所に:files (:defaults "extensions/*")
を追加します。
(use-package corfu
:straight (corfu :type git
:host github
:repo "minad/corfu"
:branch "async"
:files (:defaults "extensions/*"))
...(略)...
)
(use-package corfu-popupinfo
:straight nil
:after corfu
:hook (corfu-mode . corfu-popupinfo-mode))
yasnippet
yasnippet
のキーはcorfu
よりも優先順位が高いため、corfu
用にTAB
へキーを割り当てても動作しません。
そのため、yasnippet
のTAB
キーを無効化して、別のキーに割り当ててます。
(use-package yasnippet
:bind (nil
:map yas-keymap
("<tab>" . nil)
("TAB" . nil)
("<backtab>" . nil)
("S-TAB" . nil)
("M-}" . yas-next-field-or-maybe-expand)
("M-{" . yas-prev-field))
:init
(yas-global-mode +1))
tempel
corfuの作者のminadさんがスニペットのパッケージを作成してくれています。
corfuとの統合はcapeに載せています。
(use-package tempel
:bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
("M-*" . tempel-insert)))
終わりに
corfuは動作が軽量でカスタマイズ性が高く、設定を工夫すればcompany
と同等かそれ以上の使い勝手になります。
corfu wikiやREADMEに設定例を色々記載してくれているので、自分にあった最適な設定を見つけていきたいです。