helmからモダンなvertico + consult + recentf + orderless + marginaliaに移行してみた

2023年4月06日
thumbnail
Emacsの魅力といえばカーソル移動、バッファ移動を含めた補完UIです。元祖はanythingで僕はhelmが出た後もずいぶん長く使っていました。melpaからanythingが削除されて、helmに移動した後も、使い勝手はanythingに極力近づけて利用していました。
そんなhelmも時代的に移行が囁かれてきたので、試しによくある補完UIの構成を試してみます。
helmからconsultベースの構成に移行して唯一不満があるのはconsult-bufferでバッファを一覧を表示して、不必要なバッファを削除できないことです。helmの場合はhelm-miniバッファを表示て、buffer-run-kill-persistent(C-c d)で削除できたので便利でした。
embarkは使い方がむずかしそうだったので、私は利用していません。 それ以外はおおむね満足しています。
先に完成済みのコードをまとめておきます。
;; エコーエリア内で入力の補完をサポートする
(use-package vertico
  :ensure t
  :init
  ;; 補完候補を最大15行まで表示する
  (setq vertico-count 15)
  (vertico-mode))

;; find-file時に上のディレクトリに戻るのをサポートする
(use-package extensions/vertico-directory
  :straight (:type built-in)
  :after vertico
  :ensure nil
  :bind (:map vertico-map
              ("C-l" . vertico-directory-up)
              ("\\d" . vertico-directory-delete-char)))

;; 対話型コマンドを利用しやすくする
(use-package consult
  :ensure t
  :bind
  (("C-x C-a" . consult-buffer)            ;; anythingの名残でC-x C-aにバインド
   ("M-g M-g" . consult-goto-line)         ;; goto-lineをconsult-goto-lineに置き換え
   ("C-c s" . consult-line)                ;; バッファ内をキーワードで検索
   ("C-c o" .   consult-outline)))         ;; ファイルのアウトラインになりうる項目へ移動

;; 最近開いたファイルを参照
(use-package recentf
  :config
  (setq recentf-max-saved-items 15)              ;; consult-bufferに表示する最近使ったファイルの最大表示数
  (setq recentf-exclude '(".recentf" "^/ssh:"))  ;; recentfの履歴に含ませないファイルリスト
  (setq recentf-auto-cleanup 'never)             ;; recentfの履歴を削除しない

  (setq recentf-auto-save-timer
        (run-with-idle-timer 30 t 'recentf-save-list)) ;; バッファを開いて30秒以上したら履歴に登録
  (recentf-mode 1)
  ;; recentf の メッセージをエコーエリア(ミニバッファ)に表示しない
  ;; (*Messages* バッファには出力される)
  (defun recentf-save-list-inhibit-message:around (orig-func &rest args)
    (setq inhibit-message t)
    (apply orig-func args)
    (setq inhibit-message nil)
    'around)
  (advice-add 'recentf-cleanup   :around 'recentf-save-list-inhibit-message:around)
  (advice-add 'recentf-save-list :around 'recentf-save-list-inhibit-message:around)
  )

;; verticoの絞り込みにあいまい検索を追加
(use-package orderless
  :ensure t
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

;; consultのリストなどにメタ情報を表示する
(use-package marginalia
  :ensure t
  :init
  (marginalia-mode))

vertico

verticoは補完UIの1つです。主にユーザーと対話的エコーエリアで操作するコマンドを良い感じにしてくれます。
よく使いそうな場面を紹介します。
yank-popはEmacsでテキストを切り取ったり、コピーした情報を貼り付ける機能でM-yで起動します。Verticoはコピー、切り取り履歴もサポートします。クリップボードの絞り込みと選択が便利になっています。
article image
find-fileはファイルを探し開くコマンドでC-x C-fで起動します。エコーエリアに候補となるディレクトリとファイルが表示され、ディレクトリを移動して任意のファイルを選びエンターで開けます。verticoは入力の補完でTabが機能します。入力、候補の選択もかなり良い感じになります。
article image
switch-to-bufferは開いているバッファを切り替えるためのコマンドでC-x bを使って起動します。verticoを使っていると、エコーエリアに移動できるバッファがリストで表示されるので、ファイル名をタイプしたり、C-nC-pでカーソルを移動させて目的のバッファに切り替えます。
article image
他にも対話型なら大体verticoがサポートしてくれます。

vertico-directory

find-fileでファイルを探すときに1つ上のディレクトリに戻る方法がvertico単体だとかなりいけてないです。ディレクトリを下るときはTabで候補が補完されます。一方で、上に上がろうとすると、デリートキーを連打しなくてはなりません。helmはC-lまたはデリートキーで上の階層に移動できました。
vertico-directoryはfind-fileのディレクトリ移動をサポートする拡張機能です。C-lで1つ上の階層にサクサク移動できるのでディレクトリ移動が楽になります。

consult

consultはEmacsが提供する対話型コマンドをその名の通り相談しやすくしてくれます。verticoはあくまで入力の補完をサポートしています。consultはEmacsコマンド全体をサポートする意味合いが強いです。
consultはかなり多くの機能を提供しています。全てを説明するのは難しいのでよく使うコマンド4つを紹介します。それ以外はgithubのReadmeを読むと良いでしょう。

consult-buffer

helmやanythingでいうところのmini-bufferにあたるのがこれです。デフォルトでは現在開いているバッファのリストしか表示されませんが、カスタマイズすることで、最近開いたファイル、ブックマークしたファイルを表示できます。
多くのサイトではC-x bswitch-to-bufferを上書きを紹介しています。私はずっとhelmを使っていたのでC-x C-aにバインドしています。

consult-goto-line

consult-goto-lineは目的の行数にジャンプする機能を強化します。 本来のgoto-lineはエコーエリアで目的の行数をタイプし、エンターを押すことで移動します。一方で、consult-goto-lineは行数を入力すると、エディタにプレビューが表示されます。大変便利で、移動しようと思った場所が違った場合は、エコーエリアの行数を削除して別の数字を入力すればそっちが候補として表示されます。目的の場所が定まったらエンターを押せば移動できます。Gitの差分を見ていて、編集したいときに行数を覚えておくだけで、すぐに目的のコードに移動できるのは便利です。

consult-line

consult-lineはバッファ内を検索し、該当するテキストをリストで表示し、プレビューを表示しながら、目的の行へ移動するのをサポートしてくれます。これとよく似たEmacsの標準コマンドはisearch-forwardになります。こっちは絞り込みが弱かったり、プレビューがありません。

consult-outline

consult-outlineはファイルの見出しをざっくり候補として表示し移動できるようにしてくれます。特にMarkdownで文章を書いている場合に利用します。各ヘッダーをリスト化して表示するので、簡単に目的の文章へ飛ぶことができます。

consult-bufferに最近使ったファイルを表示

init.elrecentf-modeの設定を記述すれば、自動的にconsult-bufferに開いたファイルの履歴が載るようになります。
設定自体は、僕もよくわからなかったので、こちらの記述を参考にさせてもらいました。
recentfの設定を書いてconsult-bufferを実行すると、最近利用したファイルの一覧がバッファ一覧の下に表示されます。
article image

bookmarkを表示

Emacsは標準機能でBookmarksがあり、バッファの任意の場所をブックマークできます。ブックマークはエディタを閉じた後でも残っており、いつでも目的のブックマークにconsult-bufferでジャンプできます。
emacsのbookmarkに関する基本的なコマンドはこちらに詳しく書いてあります。
試しに.init.elの適当な行をブックマークします。 M-x bookmark-set対話が始まるので、ブックマーク名をタイプしてエンターを押します。
ブックマークを登録して、M-x consult-buffer を起動すると、一番下に登録したブックマークが表示されます。
article image
ブックマークを削除する場合はM-x bookmark-deleteで対象のブックマークを選ぶだけです。
article image

絞り込みにあいまい検索する

標準のVerticoでは対話的に候補を絞り込むときに、絞り込みは先頭からマッチするものしか入力できません。例えばM-xbook delと入力してもbookmark-deleteは補完候補として出てきません。
article image
orderlessを入れると、スペースであいまい検索が可能になります。
article image

メタ情報の表示

consult-bufferでリストを表示したり、M-xでコマンドを実行しようとしたときに、より多くのメタ情報を表示してくれるのがmarginaliaです。
marginaliaが無い状態でバッファーを表示すると、このようにシンプルです。
article image
メタ情報がありの表示。
article image

まとめ

Emacsの補完UIは時代と共にトレンドとなるパッケージは変化するけれども、GUIエディタにはないカーソル移動、ファイル移動の体験ができて、今後もずっと残っていてほしい機能です。
profile image
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。