ワタタツの日記
2021 年 6 月 15 日 (火)
☆ consultをmigemoizeしたい (未完→だいたいできた)
consultがとてもいい感じなので @rocktakey さんのivy-migemoでcounsel系をやるようにmigemo化したいです。 まずは調査調査。
ちなみに、consult, vertico, orderless, embark などの便利な組み合わせの紹介についてはとんさんのEmacsの次世代ミニバッファ補完UI | 日々、とんは語る。がおすすめです。
ivy
まずivy-migemoがなぜ適用できるかで、counsel系に使われている ivy-read
関数を見てみます。
https://github.com/abo-abo/swiper/blob/040d458bce4a88f37359192061bcea5ebe87007c/ivy.el#L2019
re-builder
というのが設定できるようになっていて、入力したクエリをさらに関数でいじることができます。
ivy-migemo では ivy-re-builders-alist
に (counsel-hogehoge . ivy-migemo--regex-plus)
などと ivy-migemo--regex-plus
を突っ込むことで各種 counsel-*
の :re-builder
に渡ってきます。
consult
一方 consult系はどうなっているでしょうか。 ivy-read
にあたるものはたぶん consult--read
とそのマルチ版 consult--multi
です。
- consult--read: https://github.com/minad/consult/blob/9e34c679a2bc39cd167a7226568dfac5b2193292/consult.el#L1794
- consult--multi: https://github.com/minad/consult/blob/9e34c679a2bc39cd167a7226568dfac5b2193292/consult.el#L1958
それで、こ consult--read
と consult--multi
には re-builder
にあたるものが、 なさそう ということまで調査しました。
現状
根元の関数 | re-builder(っぽいもの) |
---|---|
ivy-read | ある |
consult--read | ない |
という感じです。 ( ˃ ⌑ ˂ഃ )
追記: 2021-06-16
だいたいできました。 emacs-jp の Slackで orderless のソースでも読んでみようかと書いていたら、なんと orderless そのものから忍び込めることを教えていただきました。
orderless は、標準の completion-category-overrides
を定義すればカテゴリごとに補完スタイルを設定できるように作られています。標準のものを使うようにうまく出来ていますねえ。
カテゴリというのは metadata として提供されていて Emacs 28 からはたくさんついており、27以前は marginaliaが頑張ってくれるみたいです。
そこでまず command カテゴリに設定する例を教えてもらい、ちゃんと動くことがわかりました。
あとはどのコマンドがどのカテゴリで実行されるのかを調べればだいたい良いということがわかりました。
ソースコードリーディングをしたところ、次のことがわかりました。
コマンド | カテゴリ |
---|---|
execute-extended-command (M-x) | command |
find-file | file |
consult--multiを呼ぶコマンド (consult-bufferなど) | consult-multi |
consult-lineなど | consult-location |
あとは最近使っている org-roam の org-roam-find-file
はどのカテゴリになっているのかがわかりませんでした。
なんとなく marginalia を見ていたところ marginalia-prompt-categories
という変数にいろいろカテゴリが書いてあることがわかりました。
なんとプロンプトに書いてある文字列にヒットしてカテゴリを設定してしまおうというもののようです(たぶん。たぶんね。)。なので、
(add-to-list 'marginalia-prompt-categories
'("\\<File\\>" . file))
と設定しました! すると動きました! org-roam-find-file
のプロンプトには "File" と出ているからです!
勝ちました!
勝った様子
(leaf consult
:ensure t
:bind* (("M-m" . consult-buffer))
:bind (
("M-s" . consult-line)
("M-g ." . consult-ripgrep))
:config
(autoload 'projectile-project-root "projectile")
(setq consult-project-root-function #'projectile-project-root))
(leaf orderless
:ensure t
:init
(icomplete-mode)
(defun orderless-migemo (component)
(let ((pattern (migemo-get-pattern component)))
(condition-case nil
(progn (string-match-p pattern "") pattern)
(invalid-regexp nil))))
(orderless-define-completion-style orderless-default-style
(orderless-matching-styles '(orderless-literal
orderless-regexp)))
(orderless-define-completion-style orderless-migemo-style
(orderless-matching-styles '(orderless-literal
orderless-regexp
orderless-migemo)))
(setq completion-category-overrides
'((command (styles orderless-default-style))
(file (styles orderless-migemo-style))
(buffer (styles orderless-migemo-style))
(symbol (styles orderless-default-style))
(consult-location (styles orderless-migemo-style)) ; category `consult-location' は `consult-line' などに使われる
(consult-multi (styles orderless-migemo-style)) ; category `consult-multi' は `consult-buffer' などに使われる
(org-roam-node (styles orderless-migemo-style)) ; category `org-roam-node' は `org-roam-node-find' で使われる
(unicode-name (styles orderless-migemo-style))
(variable (styles orderless-default-style))))
;; (setq orderless-matching-styles '(orderless-literal orderless-regexp orderless-migemo))
:custom
(completion-styles . '(orderless)))
(leaf marginalia
:ensure t
:init
(marginalia-mode)
:config
(add-to-list 'marginalia-prompt-categories
'("\\<File\\>" . file)))
2021-10-10追記: Naoki Sakamotoさんに org-roam-node-find
のカテゴリが org-roam-node
であることを教えていただきました。感謝いたします🙏