diff options
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c index f77f07e1711..cef9407dbfa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1176,9 +1176,18 @@ Lisp_Object internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) { + /* MINIBUFFER_QUIT_LEVEL is to handle quitting from nested minibuffers by + throwing t to tag `exit'. + Value -1 means there is no (throw 'exit t) in progress; + 0 means the `throw' wasn't done from an active minibuffer; + N > 0 means the `throw' was done from the minibuffer at level N. */ + static EMACS_INT minibuffer_quit_level = -1; /* This structure is made part of the chain `catchlist'. */ struct handler *c = push_handler (tag, CATCHER); + if (EQ (tag, Qexit)) + minibuffer_quit_level = -1; + /* Call FUNC. */ if (! sys_setjmp (c->jmp)) { @@ -1192,6 +1201,23 @@ internal_catch (Lisp_Object tag, Lisp_Object val = handlerlist->val; clobbered_eassert (handlerlist == c); handlerlist = handlerlist->next; + if (EQ (tag, Qexit) && EQ (val, Qt)) + /* If we've thrown t to tag `exit' from within a minibuffer, we + exit all minibuffers more deeply nested than the current + one. */ + { + EMACS_INT mini_depth = this_minibuffer_depth (Qnil); + if (mini_depth && mini_depth != minibuffer_quit_level) + { + if (minibuffer_quit_level == -1) + minibuffer_quit_level = mini_depth; + if (minibuffer_quit_level + && (minibuf_level > minibuffer_quit_level)) + Fthrow (Qexit, Qt); + } + else + minibuffer_quit_level = -1; + } return val; } } |