Go to the first, previous, next, last section, table of contents.


Recursive Edits

Entering a recursive edit basically means to recursively call the event loop from a Lisp program, this latest instance of the event loop will work like the normal event loop (the top level event loop) until it is exited, at which point the Lisp program will regain control.

Recursive edits should be used sparingly since they can be very confusing for the user; they are mainly used to implement interactive user interfaces in the middle of a Lisp program or command. This can be achieved by installing a special set of key bindings for the duration of the recursive edit.

When programming with recursive edits a lot of care should be used; if proper cautions aren't taken an abnormal exit from a recursive error can wreak havoc.

Note that throw and catch (see section Catch and Throw) can be used through recursive edits with no problems; the recursive edit will automatically be aborted.

Command: recursive-edit
Enter a new level of recursive editing.

Function: recursion-depth
This function returns the number of recursive edits currently in progress. When in the top level this will return zero.

Command: top-level
Abort all recursive edits, control will be passed straight back to the top level event loop.

Command: abort-recursive-edit &optional edit-value
This function aborts the outermost recursive edit (but never the top level) returning edit-value (or nil) from the instance of the recursive-edit function which invoked this recursive edit.

When using recursive edits it is important to remember that the buffer and window configuration that existed when the edit was entered may not still exist when the recursive edit terminates. This means that some care has to be taken when installing and removing buffer-local values of variables. For example, the ask-y-or-n function, which uses a recursive edit, does something like this:

(let
    ;; First save the old values of the variables to be altered.
    ;; The variables can't be directly bound to since this doesn't
    ;; work properly with buffer-local variables :-(
    ((old-u-k-h unbound-key-hook)
     (old-k-p keymap-path)
     (old-buf (current-buffer)))
  ;; Now install the new values
  (setq unbound-key-hook (cons #'(lambda ()
                                   (beep)
                                   t)
                               nil)
        keymap-path '(y-or-n-keymap)
        status-line-cursor t)
  ;; This is the important bit; ensure that the old values will
  ;; be reinstated even if an abnormal exit occurs. Also note
  ;; that they are always set in the original buffer.
  (unwind-protect
      (catch 'ask
        (recursive-edit))
    (with-buffer old-buf
      (setq keymap-path old-k-p
            unbound-key-hook old-u-k-h
            status-line-cursor nil)))))


Go to the first, previous, next, last section, table of contents.