interactive ¶ の使用本節では、Lisp関数を対話的に呼び出し可能なコマンドにするためのinteractive形式の書き方と、コマンドのinteractive形式の確認方法について説明します。
この特殊形式は、関数がコマンドであり、したがって対話的に呼び出せる(M-x 経由、またはそれにバインドされたキーシーケンスの入力による)ことを宣言します。引数 arg-descriptor は、コマンドが対話的に呼び出された際に、そのコマンドへの引数をどのように計算するかを宣言します。
コマンドは、他の関数と同様にLispプログラムから呼び出すことができますが、その場合、呼び出し側が引数を指定するため、arg-descriptor は効果を発揮しません。
interactive フォームは、関数本体のトップレベル、または関数シンボルの interactive-form プロパティ(シンボルプロパティ
を参照)に配置されている必要があります。コマンドループが関数を呼び出す前にこのフォームを探すため、効果を発揮します(インタラクティブ呼び出し
を参照)。関数が呼び出されると、その本体内のすべてのフォームが実行されます。このとき、本体内に interactive フォームが存在する場合、そのフォームは引数を評価することなく単に nil を返します。
modes リストを使用すると、コマンドをどのモードで使用させるかを指定できます。modes を指定した際の効果や使用タイミングの詳細については、コマンドのモード指定を参照してください。
慣例として、interactive
フォームは関数本体の最初のトップレベルフォームとして配置すべきです。interactive-form
シンボルプロパティと関数本体の両方に interactive
フォームが存在する場合、前者が優先されます。interactive-form
シンボルプロパティを使用すると、関数を再定義することなく、既存の関数にインタラクティブフォームを追加したり、引数のインタラクティブな処理方法を変更したりできます。
引数 arg-descriptor には3つの可能性があります。
nil
と指定でき、その場合は引数なしでコマンドが呼び出されます。コマンドが1つ以上の引数を必要とする場合、すぐにエラーが発生します。
interactive
のコード文字を参照)で構成され、その後に任意でプロンプトが続きます(一部のコード文字ではプロンプトを使用し、一部では無視します)。以下に例を示します。
(interactive "P\nbFrobnicate buffer: ")
コード文字 ‘P’ は、コマンドの第1引数を生のコマンドプレフィックスに設定します(プレフィックスコマンド引数を参照)。‘bFrobnicate buffer: ’ は、‘Frobnicate buffer: ’ を用いてユーザーに既存バッファ名の入力を促し、その名前が第2引数かつ最後の引数となります。
プロンプト文字列では、‘%’
を使用して、直前の引数の値(第1引数から)をプロンプトに含めることができます。これは format-message を用いて行われます(書式指定文字列を参照)。例えば、既存のバッファ名を読み取った後、そのバッファに指定する新しい名前を入力する方法は以下の通りです。
(interactive "bBuffer to rename: \nsRename buffer %s to: ")
文字列の先頭に ‘*’ が現れる場合、バッファが読み取り専用であればエラーが通知されます。
文字列の先頭に ‘@’ が現れ、かつコマンドの実行に用いられるキーシーケンスにマウスイベントが含まれている場合、コマンドが実行される前に、それらのイベントのうち最初のものに関連付けられたウィンドウが選択されます。
文字列の先頭に ‘^’ があり、かつコマンドが シフト変換
経由で呼び出された場合は、コマンドを実行する前にマークを設定し、一時的にリージョンをアクティブにするか、あるいは既にアクティブなリージョンを拡張します。シフト変換なしでコマンドが呼び出され、かつリージョンが一時的にアクティブな場合は、コマンドを実行する前にリージョンを非アクティブにします。シフト変換はユーザーレベルで
shift-select-mode によって制御されます。The GNU Emacs Manual の Shift
Selection を参照してください。
‘*’、‘@’、および^は組み合わせて使用でき、順序は問いません。引数の実際の読み取りは、プロンプト文字列の残りの部分(‘*’、‘@’、または‘^’以外の最初の文字から始まる部分)によって制御されます。
引数の値として point や the mark を指定することも一般的ですが、そうするとともに入力を読み取る場合(ミニバッファを使用するかどうかにかかわらず)、読み取り後に point や the mark の整数値を必ず取得するようにしてください。現在のバッファにはサブプロセスの出力が届いている可能性があり、コマンドが入力を待機している間にサブプロセスの出力が届くと、point や the mark が移動してしまう恐れがあります。
やってはいけない例を以下に挙げます:
(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である場合にのみ呼び出されることです(Open
Closuresを参照)。その目的は、一部のOClosure型において、インタラクティブ形式をスロットの一つに保持するのではなく、動的に計算できるようにすることにあります。
これは、例えば kmacro
関数において、すべて共通のインタラクティブフォームを持つため、そのメモリサイズを削減する目的で使用されます。また、インタラクティブフォームが構成要素のインタラクティブフォームから計算される
advice
関数においても使用されており、これにより計算をより遅延的に行い、構成要素のいずれかが再定義された際にインタラクティブフォームを正しく調整できるようになっています。