main-loop と {exit,quit}-recursive-edit

昔見つけたのをちょいと調べてみた。

main-loop

呼び出すと、現在実行中の処理をポーズしたまま xyzzy が操作を受け付けるようになる。ミニバッファに突入しない read-string みたいな感じ。

{exit,quit}-recursive-edit

main-loop のポーズを解除して元の処理を再開する。exit-recursive-edit は引数の値を (main-loop) の戻り値として元の処理の方に渡せる。ただし多値は使えない。quit-recursive-edit は引数を受け付けるものの行方不明になってしまう。

制限

使うと色々面白いことができそうだけど、何度も (main-loop) すると実行途中でポーズされた処理がスタックしていくので、最期にポーズした処理からしか再開できない。

試してみる

最初の (let ...) を評価すると "1: before main-loop..." が出力されたところで操作できるようになるので、下に移動して (exit-recursive-edit :hello) すると "2: main-loop returned..." と "3: after main-loop..." が出力される。

(let ((x 3))
  (format t "1: before main-loop: ~S~%" x)
  (format t "2: main-loop returned:~%  => ~S~%" (main-loop))
  (format t "3: after main-loop: ~S~%" x))
1: before main-loop: 3
2: main-loop returned:
  => :hello
3: after main-loop: 3

(exit-recursive-edit :hello)
=> nil

exit-recursive-edit すると lisp の処理は元の処理に戻るけど、エディタの状態(現在のバッファとかカーソル位置とか)は元に戻らないみたい。