次: , 前: Waiting, 上: Command Loop


20.9 中断

Lisp関数が動作中にC-gを打つと、 Emacsがなにを行っていても中断を引き起こします。 つまり、もっとも内側の活性なコマンドループに制御が戻ります。

コマンドループがキーボード入力を待っているときにC-gを打っても、 中断を引き起こさずに、普通の入力文字として動作します。 もっとも単純な場合、C-gはコマンドkeyboard-quitを実行しますが、 その効果は中断を引き起こすことですから、読者には区別できないはずです。 しかし、プレフィックスキーに続けてC-gを打つと、 それらは組み合わされて未定義キーになります。 その効果は、前置引数を含めてプレフィックスキーを取り消します。

ミニバッファでは、C-gには別の定義があって、 ミニバッファを強制終了させます。 つまり、ミニバッファから抜け出て中断します。 (単に中断したのでは、ミニバッファ内で コマンドループに戻るだけである。) コマンドループで入力を読んでいるときにC-gで直接中断しない理由は、 このようにミニバッファでその意味を再定義できるようにするためです。 ミニバッファでは、プレフィックスキーに続くC-gは再定義してなく、 プレフィックスキーと前置引数を取り消すという通常の効果を持ちます。 C-gがつねに直接中断するのでは、このようにすることさえ不可能です。

C-gが直接に中断するときには、 変数quit-flagtを設定します。 Emacsはこの変数を適切なときに検査しnilでないと中断します。 したがって、quit-flagnil以外を設定すると 中断を引き起こします。

Cのコードのレベルでは、どこでも中断できるわけではありません。 quit-flagを検査している特別な箇所だけです。 このようにするのは、それ以外の箇所で中断すると Emacsの内部状態に矛盾をきたす可能性があるからです。 中断は安全な場所まで延期されるので、 中断によってEmcasがクラッシュすることはありません。

read-key-sequenceread-quoted-charなどのある種の関数は、 入力を待っている場合であっても中断を完全に抑制します。 中断するかわりに、C-gは入力として働きます。 read-key-sequenceの場合、コマンドループにおいて C-gの特別なふるまいをもたらします。 read-quoted-charの場合、 C-qC-gをクォートできるようになります。

変数inhibit-quitnil以外の値を束縛することで Lisp関数のある部分において中断を抑制できます。 そうすると、C-gはそれでもいつもどおり quit-flagtにしますが、 その通常の結果である中断は抑制されます。 最終的にフォームletの終りで束縛が解除されるなどして inhibit-quitが再度nilになります。 その時点でもquit-flagnil以外であると 要求した中断がただちに起こります。 このふるまいは、プログラムの『臨界領域』では 中断が起こらないことを保証する理想的なものです。

read-quoted-charなどの)ある種の関数では、 C-gは特別に処理され中断を引き起こしません。 inhibit-quittを束縛して入力を読み取り、 inhibit-quitが再度nilになるまえに quit-flagnilにすることでそのようにします。 これをread-quoted-charの定義の以下の抜粋で示しましょう。 最初の入力文字のあとで通常の中断を許す方法も示しています。

     (defun read-quoted-char (&optional prompt)
       "...documentation..."
       (let ((message-log-max nil) done (first t) (code 0) char)
         (while (not done)
           (let ((inhibit-quit first)
                 ...)
     	(and prompt (message "%s-" prompt))
     	(setq char (read-event))
     	(if inhibit-quit (setq quit-flag nil)))
     
           ...変数codeに設定する...)
         code))
— 変数: quit-flag

inhibit-quitnilであれば、 この変数がnil以外であるとEmacsはただちに中断する。 C-gは、inhibit-quitに関わらず、 通常、quit-flagnil以外を設定する。

— 変数: inhibit-quit

この変数は、quit-flagnil以外の値に設定されたときに Emacsが中断すべきかどうかを決定する。 inhibit-quitnil以外であると、 quit-flagに特別な意味はない。

— コマンド: keyboard-quit

この関数は(signal 'quit nil)quit条件を通知する。 これは中断と同じことを行う。 (Errorssignalを参照。)

中断として使うC-g以外の特殊文字を使えます。 Terminal Inputの関数set-input-modeを参照してください。