インタラクティブ指定子

refenerce を見ると *interactive-specifier-alist* に追加すればとか keymap.l 参照とか書いてあるので見てみたり調べてみたりしたのでメモ。

えーと、*interactive-specifier-alist* に '(キー . 関数のシンボル) を追加すれば キー の文字が指定子として使えるようになり、その指定子を指定された interactive なコマンドを実行すると、指定された関数が呼び出される。
その関数は

  • 引数として以下が与えられる
    • プロンプト文字列: (interactive "Tprompt") なら "prompt"
    • :defaultN に与えられたもの
    • :historyN に与えられたもの
    • :titleN に与えられたもの
  • (list 引数としたい値) を返すべし

今回はいくつかのキーワードシンボルからどれかを選ぶようなのが欲しかったので。

(defun interactive-keyword-symbol (prompt default history title)
  (multiple-value-bind (candidates must-match)
      (cond ((listp title) (values title t))
            ((and (symbolp title) (listp (symbol-value title)))
             (values (symbol-value title) t))
            (t (values nil nil)))
    (list
     (intern (completing-read prompt candidates :history history
                              :default default :must-match must-match)
             (find-package "keyword")))))

(pushnew '(#\K . interactive-keyword-symbol)
         *interactive-specifier-alist* :test #'equal)

「いくつかのキーワードシンボル」をどうやって渡そうか困ったのだが、使い道のわからない :titleN を流用して、候補を与えられたらその中から(:must-match t)、そうでなけりゃなんでも、としておいた。default と history はふつーに使える。

(defun foo (arg)
  (interactive "Kfoo? " :default0 "foo" :title0 '(:foo bar baz))
  arg)

M-x foo するとミニバッファに "foo? foo" となって、foo bar baz から補完とかできる。