背景
【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
- lsp-mode
corfu
まずは基本となるcorfuを設定します。
※私はrust-analyzer
やcompany-tabnine
のように入力に応じて、補完候補が変化する状況があったので、async
ブランチを採用しています。
(use-package corfu
:straight (corfu :type git
:host github
:repo "minad/corfu"
:branch "async"
:files (:defaults "extensions/*"))
:custom ((corfu-auto t)
(corfu-auto-prefix 1)
(corfu-auto-delay 0)
(corfu-cycle t)
(tab-always-indent 'complete))
:bind (nil
:map corfu-map
("RET" . nil)
("<return>" . nil)
("TAB" . corfu-insert)
("<tab>" . corfu-insert))
: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の補完が出るようにします。
(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))
cape
次にcapeを設定します。
corfuだけでも使用できますが、completion-at-point
を自分好みにカスタマイズしたり、様々なcompletion-at-point
を追加することができるようになります。今回はcompany-yasnippet
やcompany-tabnine
等も組み合わせています。
※ company-tabnine
は非同期モードを搭載したkarta0807913さんのリポジトリを使用しています。
(use-package company-tabnine
:straight (company-tabnine :type git :host github :repo "karta0807913/company-tabnine"))
(use-package cape
:straight t
:hook ((prog-mode . my/set-basic-capf)
(text-mode . my/set-basic-capf)
(meghanada-mode . my/set-meghanada-capf)
(lsp-completion-mode . my/set-lsp-capf))
:config
(defun my/convert-super-capf (arg-capf)
(list (cape-capf-case-fold
(cape-super-capf arg-capf
(cape-company-to-capf #'company-yasnippet)
(cape-company-to-capf #'company-tabnine)))
#'cape-file
#'cape-dabbrev))
(defun my/set-basic-capf ()
(setq-local completion-at-point-functions (my/convert-super-capf (car completion-at-point-functions))))
(defun my/set-meghanada-capf ()
(setq-local completion-at-point-functions (my/convert-super-capf (cape-company-to-capf #'company-meghanada))))
(defun my/set-lsp-capf ()
(setq-local completion-at-point-functions (my/convert-super-capf #'lsp-completion-at-point)))
(add-to-list 'completion-at-point-functions (cape-company-to-capf #'company-tabnine) t)
(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-capf-case-fold
は大文字小文字を区別しないようにしてくれます。 -
cape-super-capf
は複数のcompletion-at-pointを一つにまとめることができます。 - Javaの開発に
meghanada
を使用している場合はcompany-meghanada
をcape-company-to-capf
でcapfに変換します。
※これまでcape-capf-buster
を使用して候補の最新化を図っていましたが、corfu
のasync
ブランチがいい感じに動作してくれているので、現在は使用していません。
orderless
次にorderlessを設定します。
Emacs標準の補完スタイルのflex
でも構いませんが、orderless
のほうが絞り込み速度が早く、後述のprescient
と組み合わせることで使い勝手も向上します。
(use-package orderless
:straight t
:custom ((completion-styles '(orderless))
(completion-category-defaults nil)
(completion-category-overrides nil))
:hook (corfu-mode . (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
:straight t
:config
(prescient-persist-mode +1))
(use-package corfu-prescient
:straight t
:after corfu
:init
(with-eval-after-load 'orderless
;; prescientではなく、補完スタイルを使用して絞り込む
(setq corfu-prescient-enable-filtering nil
corfu-prescient-override-sorting t))
(corfu-prescient-mode +1))
kind-icon
corfuにアイコンをつけるパッケージです。
(use-package kind-icon
:straight t
: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
を使用している場合は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
:after corfu
:config
(corfu-popupinfo-mode +1))
yasnippet
yasnippet
のキーはcorfu
よりも優先順位が高いため、corfu
用にTAB
へキーを割り当てても動作しません。
そのため、yasnippet
のTAB
キーを無効化して、別のキーに割り当ててます。
(use-package yasnippet
:straight t
:bind (nil
:map yas-keymap
("<tab>" . nil)
("TAB" . nil)
("<backtab>" . nil)
("S-TAB" . nil)
("C-o" . yas-next-field-or-maybe-expand))
:init
(yas-global-mode +1))
lsp-mode
lsp-modeはデフォルトでcompanyが起動しますが、corfuが起動するように設定を追加します。
(use-package lsp-mode
:straight t
:custom ((lsp-keymap-prefix "M-l")
(lsp-signature-auto-activate '(:on-trigger-char :after-completion :on-server-request))
(lsp-idle-delay 1.0)
(lsp-semantic-tokens-enable t)
(lsp-completion-provider :none) ;; ★補完にcorfuを使用する
)
:hook ((lsp-mode . lsp-enable-which-key-integration)
(html-mode . lsp)
(css-mode . lsp)
(rust-mode . lsp)
(nxml-mode . lsp)
(java-mode . lsp)
(js-mode . lsp)))
終わりに
corfuは動作が軽量でカスタマイズ性の高い良いパッケージです。
設定を工夫すればcompany
と同等かそれ以上の使い勝手になります。
今後非同期機能がmain
ブランチに統合される事を願ってます。
コメント