Next: , Previous: , Up: コマンドループ   [Contents][Index]


22.13 再帰編集

Emacsはスタートアップ時に、自動的にEmacsコマンドループに移行します。このトップレベルのコマンドループ呼び出しは決してexitすることなく、Emacs実行中は実行を継続します。Lispプログラムもコマンドループを呼び出せます。これは複数のコマンドループを活性化するので、再帰編集(recursive editing)と呼ばれています。再帰編集レベルは呼び出したコマンドが何であれそれをサスペンドして、そのコマンドを再開する前にユーザーが任意の編集を行うことを可能にする効果をもちます。

再帰編集の間に利用可能なコマンドは、トップレベルの編集ループ内で利用できるコマンドと同じでありキーマップ内で定義されます。数少ない特別なコマンドだけが再帰編集レベルをexitして、他のコマンドは再帰編集レベルが終了したときに再帰編集レベルからリターンします(exitするための特別なコマンドは常に利用できるが再帰編集が行われていないときは何も行わない)。

再帰コマンドループを含むすべてのコマンドループは、コマンドループから実行されたコマンド内のエラーによってそのループをexitしないように、汎用エラーハンドラーをセットアップします。

ミニバッファー入力は特殊な再帰編集です。これはミニバッファーとミニバッファーウィンドウの表示を有効にするなどの欠点をもちますが、それはあなたが思うより少ないでしょう。ミニバッファー内では特定のキーの振る舞いが異なりますが、これははミニバッファーのローカルマップによるものです。ウィンドウを切り替えれば通常のEmacsコマンドを使用できます。

再帰編集レベルを呼び出すには関数recursive-editを呼び出します。この関数はコマンドループを含んでいます。さらにexitをthrowすることにより再帰編集レベルのexitを可能にする、タグexitをともなったcatch呼び出しも含んでいます(明示的な非ローカル脱出: catchthrowを参照)。コマンドC-M-c (exit-recursive-edit)がこれを行います。値tをthrowすることによってrecursive-editがquitされるので、1レベル上位のコマンドループに制御がリターンされます。これはabortと呼ばれ、C-](abort-recursive-edit)がこれを行います。同様にrecursive-editにエラーをシグナルさせるために文字列値をthrowできます。この文字列はメッセージとしてプリントされます。関数値をthrowすると。recursive-editはリターンする前に引数なしでそれを呼び出します。それ以外の値をthrowすると、recursive-editは自身を呼び出した関数に正常にリターンします。コマンドC-M-c (exit-recursive-edit)がこれを行います。

ほとんどのアプリケーションはミニバッファー使用の一部として使用する場合を除き、再帰編集を使用するべきではありません。カレントバッファーのメジャーモードから特殊なメジャーモードに一時的に変更する場合に、そのモードに戻るコマンドをもつ必要があるときは、通常は再帰編集のほうが便利です(Rmailのeコマンドはこのテクニックを使用)。またはユーザーが新たなバッファーの特殊なモードで、異なるテキストを再帰的に編集・作成・選択できるようにしたい場合が該当します。このモードでは処理を完了させるコマンドを定義して前のバッファーに戻ります(Rmailのmコマンドはこれを使用)。

再帰編集はデバッグに便利です。一種のブレークポイントとして関数定義内にdebugを挿入して、関数がそこに達したときにその箇所を調べることができます。debugは再帰編集を呼び出しますが、デバッガのその他の機能も提供します。

query-replace内でC-rをタイプしたときやC-x q (kbd-macro-query)を使用したときにも再帰編集レベルが使用されます。

Command: recursive-edit

この関数はエディターコマンドループを呼び出す。これはユーザーに編集を開始させるために、Emacsの初期化により自動的に呼び出される。Lispプログラムから呼び出されたときは再帰編集レベルにエンターする。

カレントバッファーが選択されたウィンドウのバッファーと異なる場合、recursive-editはカレントバッファーの保存とリストアを行う。それ以外ではバッファーを切り替えると、recursive-editがリターンした後にその切り替えたバッファーがカレントになる。

以下の例では関数simple-recが最初にポイントを1単語分進めてからメッセージをエコーエリアにプリントして再帰編集にエンターする。その後ユーザーは望む編集を行い、C-M-cをタイプすれば再帰編集をexitしてsimple-recの実行を継続できる。

(defun simple-rec ()
  (forward-word 1)
  (message "Recursive edit in progress")
  (recursive-edit)
  (forward-word 1))
     ⇒ simple-rec
(simple-rec)
     ⇒ nil
Command: exit-recursive-edit

この関数は最内の再帰編集(ミニバッファー入力を含む)からexitする。関数の実質的な定義は(throw 'exit nil)

Command: abort-recursive-edit

この関数は再帰編集をexitした後にquitをシグナルすることにより、最内の再帰編集(ミニバッファー入力を含む)を要求したコマンドをabortする。関数の実質的な定義は(throw 'exit t)quitを参照のこと。

Command: top-level

この関数はすべての再帰編集レベルをexitする。これはすべての計算を直接抜け出してメインのコマンドループに戻って値をリターンしない。

Function: recursion-depth

この関数は再帰編集のカレントの深さをリターンする。アクティブな再帰編集が存在しなければ0をリターンする。