interactive
の使用 ¶このセクションでは、Lisp関数をインタラクティブに呼び出し可能なコマンドにするinteractive
フォームの記述方法と、コマンドのinteractive
フォームの検証方法について説明します。
このスペシャルフォームは関数がコマンドであり、したがって(M-xを通じて、またはそのコマンドにバインドされたキーシーケンスをエンターすることにより)インタラクティブに呼び出すことができることを宣言する。引数arg-descriptorは、そのコマンドがインタラクティブに呼び出されたときに引数を計算する方法を宣言する。
コマンドは他の関数と同じようにLisp関数から呼び出されるかもしれないが、その場合には呼び出し側は引数を提供して、arg-descriptorは効果をもたない。
interactive
フォームは関数body内のトップレベルに置くか、関数シンボルのinteractive-form
プロパティ((シンボルのプロパティ)を参照)になければならない。これはコマンドループが関数を呼び出す前にinteractiveフォームを調べることにより効果をもつ(インタラクティブな呼び出しを参照)。一度関数が呼び出されると関数body内のすべてのフォームが実行される。このときbody内にinteractive
フォームが出現しても、そのフォームは引数の評価さえされず単にnil
をリターンする。
modesリストではコマンドの使用を意図したモードを指定できる。modes指定の効果と使用するタイミングに関する詳細はコマンドにたいするモード指定を参照のこと。
慣例によりinteractive
フォームは関数body内の最初のトップレベルフォームとするべきである。interactive
フォームがシンボルのinteractive-form
プロパティと関数bodyの両方に存在する場合には前者が優先される。interactive-form
フォームは既存の関数にinteractiveフォームを追加したり、その関数を再定義することなく引数をインタラクティブに処理する方法を変更するために使用できる。
引数arg-descriptorは以下の3つの可能性があります:
nil
ならコマンドは引数なしで呼び出される。コマンドが1つ以上の引数を要求する場合は即座にエラーとなる。
interactive
にたいするコード文字を参照)と、オプションでその後のプロンプト(コード文字として使用される文字やコード文字としては無視されるものもある)により構成される。以下は例である:
(interactive "P\nbFrobnicate buffer: ")
コード文字‘P’はそのコマンドの1つ目の引数をrawコマンドプレフィクス(プレフィクスコマンド引数を参照)にセットする。‘bFrobnicate buffer: ’は、ユーザーに‘Frobnicate buffer: ’のプロンプトを示して既存のバッファーの名前の入力を促し、これは2つ目かつ最後の引数になる。
プロンプト文字列には、プロンプト内の前の引数(1つ目の引数から始まる)の値を含めるために‘%’を使用できる。これはformat-message
(文字列のフォーマットを参照)を使用して行われる。たとえば以下は既存のバッファーの名前を読み取って、その後にそのバッファーに与える新たな名前を読み取る例である:
(interactive "bBuffer to rename: \nsRename buffer %s to: ")
文字列の先頭に‘*’がある場合、そのバッファーが読み取り専用ならエラーがシグナルされる。
文字列の先頭が‘@’で、そのコマンドの呼び出しに使用されたキーシーケンスに何らかのマウスイベントが含まれる場合は、そのコマンドを実行する前に、それらのうち最初のイベントに結びつくウィンドウが選択される。
文字列の先頭が‘^’で、そのコマンドがシフト転換(shift-translation)を通じて呼び出された場合は、そのコマンドを実行する前にマークをセットして一時的にリージョンをアクティブにするか、すでにアクティブなリージョンを拡張する。コマンドがシフト転換なしで呼び出されて、リージョンが一時的にアクティブな場合は、コマンドを実行する前にそのリージョンを非アクティブにする。シフト転換はshift-select-mode
によりユーザーレベルで制御される。Shift
Selection in The GNU Emacs Manualを参照のこと。
‘*’、‘@’、^
は一緒に使用でき、その場合は順序に意味はない。実際の引数の読み取りは残りのプロンプト文字列(‘*’、‘@’、^
以外の最初の文字以降)により制御される。
引数値としてポイントやマークを提供するのも一般的だが、何かを行いかつ(ミニバッファー使用の有無に関わらず)入力を読み取る場合には、読み取りの前にポイント値またはマーク値の整数を確実に取得しておくこと。カレントバッファーはサブプロセスの出力を受信するかもしれず、コマンドが入力を待つ間にサブプロセス出力が到着すると、ポイントやマークの再配置が起こり得る。
以下は行ってはいけない例である:
(interactive (list (region-beginning) (region-end) (read-string "Foo: " nil 'my-history)))
これにたいして以下はキーボード入力を読み取った後にポイントとマークを調べることにより、上記の問題を避ける例である:
(interactive (let ((string (read-string "Foo: " nil 'my-history))) (list (region-beginning) (region-end) string)))
警告:
引数値にはプリントや読み取りが不可能なデータ型を含めないこと。いくつかの機能は後続のセッションに読み込ませるためにcommand-history
をファイルに保存する。コマンドの引数に‘#<…>’構文を使用してプリントされるデータ型が含まれていると、それらの機能は動作しなくなるだろう。
しかしこれには少数の例外がある。(point)
、(mark)
、(region-beginning)
、(region-end)
などの一連の式に限定して使用することに問題はない。なぜならEmacsはこれらを特別に認識して、コマンドヒストリー内に(値ではなく)その式を配置すからである。記述した式がこれらの例外に含まれるかどうか確認するには、コマンドを実行した後に(car
command-history)
を調べればよい。
この関数はfunctionのinteractive
フォームをリターンする。functionがインタラクティブに呼び出し可能な関数(インタラクティブな呼び出しを参照)なら、値はそのコマンドの引数を計算する方法を指定するinteractive
フォーム((interactive
spec)
)である。それ以外なら値はnil
。functionがシンボルなら、そのシンボルの関数定義が使用される。OClosureで呼び出された場合には、処理はジェネリック関数oclosure-interactive-form
に委譲される。
この関数はinteractive-form
と同様にコマンドを受け取り、そのインタラクティブなフォームをリターンする。これがジェネリック関数であること、そしてfunctionがOClosureのときだけ呼び出される点が異なる。この関数の目的は一部のOClosureタイプ(オープンクロージャを参照)にたいしてそれらのスロットの1つにインタラクティブフォームを格納するのではなく、動的なインタラクティブフォームの計算を可能にすることにある。
これはたとえばすべてのkmacro
は同じインタラクティブフォームを共有するので、kmacro
に用いることでメモリーサイズを削減できる。インタラクティブフォームが関数のコンポーネントのインタラクティブフォームから計算されるadvice
関数においても、いずれかのコンポーネントが再定義された際の計算を更に遅延でき、かつインタラクティブフォームをより正確に調整できる。