minibuffer で何かする
コマンドとか実行中に minibuffer で入力させて文字列を受け取るのに、なんか色々する方法。
単に文字列を入力させるなら `completing-read` 使えばいいんだけど、キーマップを変更したりインクリメンタルに何かしたりするには `*enter-minibuffer-hook*` と `*exit-minibuffer-hook*` を使う。
*enter-minibuffer-hook*
`completing-read` とか `(interactive)` で minibuffer からなんか読み取るようなコマンドで minibuffer に突入する前に実行される hook。
引数として
- minibuffer 内で使う buffer
- ヒストリ変数のシンボル
が渡される。この hook が走る時点では current-buffer は元の buffer のままなので、(`save-excursion` なりしといて)受け取った buffer に `set-buffer` してしまえば、あとは `use-keymap` とか `(setq keyword-hash-table ...)` とか好きにすればいい。
*exit-minibuffer-hook*
minibuffer で入力終わった後に呼ばれる。引数は
- minibuffer で使った buffer
- minibuffer に入力された文字列
が与えられる。デフォルトで epilogue-minibuffer という関数が登録されてて、ヒストリを更新したりしてる。
使い方
特定の場合だけ minibuffer で変なことさせるには
A: *enter-minibuffer-hook* の中で判別
`completing-read` とかで :history に指定したシンボルをチェックするとか、あるいはなんかフラグ立てといてそのフラグをチェックするとか。
(add-hook '*enter-minibuffer-hook* (defun setup-magical-minibuffer (buff hist) (when (eq hist 'magical) ...)))
B: *enter-minibuffer-hook* をローカライズ
`let` で `*enter-minibeffer-hook*` をローカライズ*1して、ローカルな `*enter-minibuffer-hook*` に `add-hook` すると、ここで `add-hook` された関数は `let` から抜けると消えてくれる。
(defun do-magical-stuff-with-minibuffer () (let ((*enter-minibuffer-hook* *enter-minibuffer-hook*)) (add-hook '*enter-minibuffer-hook* (defun setup-magical-minibuffer () ...)) (completing-read "> " nil)))