From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#49700: 27.2; [PATCH] Refactor minibuffer aborting Date: Sun, 19 Sep 2021 19:30:24 +0000 Message-ID: References: <87pmvaar0a.fsf@miha-pc> <87im0qrmxe.fsf@miha-pc> <87eeb6b3av.fsf@miha-pc> <87pmt6ho20.fsf@miha-pc> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="29589"; mail-complaints-to="usenet@ciao.gmane.io" Cc: acm@muc.de, 49700@debbugs.gnu.org To: miha@kamnitnik.top Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Sep 19 21:31:13 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mS2Wu-0007YD-84 for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 19 Sep 2021 21:31:12 +0200 Original-Received: from localhost ([::1]:52762 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mS2Wt-0007QJ-6K for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 19 Sep 2021 15:31:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:36880) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mS2Wk-0007Pw-Nf for bug-gnu-emacs@gnu.org; Sun, 19 Sep 2021 15:31:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:56682) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mS2Wk-0008Be-F9 for bug-gnu-emacs@gnu.org; Sun, 19 Sep 2021 15:31:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mS2Wk-0003NQ-86 for bug-gnu-emacs@gnu.org; Sun, 19 Sep 2021 15:31:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 19 Sep 2021 19:31:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 49700 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 49700-submit@debbugs.gnu.org id=B49700.163207983512948 (code B ref 49700); Sun, 19 Sep 2021 19:31:02 +0000 Original-Received: (at 49700) by debbugs.gnu.org; 19 Sep 2021 19:30:35 +0000 Original-Received: from localhost ([127.0.0.1]:39994 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mS2WI-0003Ml-HH for submit@debbugs.gnu.org; Sun, 19 Sep 2021 15:30:35 -0400 Original-Received: from colin.muc.de ([193.149.48.1]:22622 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1mS2WF-0003MX-9H for 49700@debbugs.gnu.org; Sun, 19 Sep 2021 15:30:32 -0400 Original-Received: (qmail 26540 invoked by uid 3782); 19 Sep 2021 19:30:24 -0000 Original-Received: from acm.muc.de (p2e5d5c04.dip0.t-ipconnect.de [46.93.92.4]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 19 Sep 2021 21:30:24 +0200 Original-Received: (qmail 17712 invoked by uid 1000); 19 Sep 2021 19:30:24 -0000 Content-Disposition: inline In-Reply-To: <87pmt6ho20.fsf@miha-pc> X-Submission-Agent: TMDA/1.3.x (Ph3nix) X-Primary-Address: acm@muc.de X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:214782 Archived-At: Hello, Miha. Apologies for loosing track of this thread a few weeks ago. I spent quite some time trying to find things wrong with your latest patch, but couldn't. ;-) So although I haven't fully tested it, I would be in favour of merging it to master. -- Alan Mackenzie (Nuremberg, Germany). On Fri, Sep 17, 2021 at 23:47:35 +0200, miha@kamnitnik.top wrote: > miha--- via "Bug reports for GNU Emacs, the Swiss army knife of text > editors" writes: > > True, my code would indeed be incorrect if the number of minibuffer > > levels to be aborted weren't to match the number of recursive edits. > > However, in such cases, my code isn't reached because an error is > > signaled that the current minibuffer isn't in the innermost command > > loop. > > Sorry for not clarifying this earlier. Would it would be enough to > > include the following comment in the code?: > > /* Due to the above check, the current minibuffer is in the most nested > > command loop, which means that we don't have to abort any extra > > non-minibuffer recursive edits. Thus, the number of recursive edits > > we have to abort equals the number of minibuffers we have to abort. > > */ > > [...] > > Perhaps the following adjustment to the doc string could be considered > > (to be applied on top of the latest patch). It copies the beginning of > > abort-recursive-edit's doc string and removes the link to it. > > [...] > I realized that my proposals are kind of scattered over multiple e-mails > in this thread. So I'm sending them again, attached in this mail as > complete patches that apply to current master. > The first patch refactors abort-minibuffers > (and improves minibuffer-quit-recursive-edit's doc string as requested). > The second patch improves documentation of recursive editing. > Best regards. > From fd5be298c67157822b35cd0231c65691c48dc29e Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= > Date: Sat, 31 Jul 2021 13:44:21 +0200 > Subject: [PATCH] Refactor minibuffer aborting > * lisp/minibuffer.el (minibuffer-quit-recursive-edit): New optional > argument to specify how many levels of recursion to quit. > * src/minibuf.c (Fabort_minibuffers): Use > minibuffer-quit-recursive-edit to quit multiple levels of minibuffer > recursion. > * src/eval.c (internal_catch): Remove special handling of 'exit tag. > --- > lisp/minibuffer.el | 20 ++++++++++++-------- > src/eval.c | 22 ---------------------- > src/lisp.h | 1 - > src/minibuf.c | 9 +++++++-- > 4 files changed, 19 insertions(+), 33 deletions(-) > diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el > index 9668e7c732..b5c0054a3c 100644 > --- a/lisp/minibuffer.el > +++ b/lisp/minibuffer.el > @@ -2349,14 +2349,18 @@ minibuffer-restore-windows > > (add-hook 'minibuffer-exit-hook 'minibuffer-restore-windows) > > -(defun minibuffer-quit-recursive-edit () > - "Quit the command that requested this recursive edit without error. > -Like `abort-recursive-edit' without aborting keyboard macro > -execution." > - ;; See Info node `(elisp)Recursive Editing' for an explanation of > - ;; throwing a function to `exit'. > - (throw 'exit (lambda () > - (signal 'minibuffer-quit nil)))) > +(defun minibuffer-quit-recursive-edit (&optional levels) > + "Quit the command that requested this recursive edit or minibuffer input. > +Do so without terminating keyboard macro recording or execution. > +LEVELS specifies the number of nested recursive edits to quit. > +If nil, it defaults to 1." > + (unless levels > + (setq levels 1)) > + (if (> levels 1) > + ;; See Info node `(elisp)Recursive Editing' for an explanation > + ;; of throwing a function to `exit'. > + (throw 'exit (lambda () (minibuffer-quit-recursive-edit (1- levels)))) > + (throw 'exit (lambda () (signal 'minibuffer-quit nil))))) > > (defun self-insert-and-exit () > "Terminate minibuffer input." > diff --git a/src/eval.c b/src/eval.c > index 48104bd0f4..76fe671b6d 100644 > --- a/src/eval.c > +++ b/src/eval.c > @@ -1174,14 +1174,6 @@ #define clobbered_eassert(E) verify (sizeof (E) != 0) > FUNC should return a Lisp_Object. > This is how catches are done from within C code. */ > > -/* MINIBUFFER_QUIT_LEVEL is to handle quitting from nested minibuffers by > - throwing t to tag `exit'. > - 0 means there is no (throw 'exit t) in progress, or it wasn't from > - a minibuffer which isn't the most nested; > - N > 0 means the `throw' was done from the minibuffer at level N which > - wasn't the most nested. */ > -EMACS_INT minibuffer_quit_level = 0; > - > Lisp_Object > internal_catch (Lisp_Object tag, > Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) > @@ -1189,9 +1181,6 @@ internal_catch (Lisp_Object tag, > /* This structure is made part of the chain `catchlist'. */ > struct handler *c = push_handler (tag, CATCHER); > > - if (EQ (tag, Qexit)) > - minibuffer_quit_level = 0; > - > /* Call FUNC. */ > if (! sys_setjmp (c->jmp)) > { > @@ -1205,17 +1194,6 @@ internal_catch (Lisp_Object tag, > Lisp_Object val = handlerlist->val; > clobbered_eassert (handlerlist == c); > handlerlist = handlerlist->next; > - if (EQ (tag, Qexit) && EQ (val, Qt) && minibuffer_quit_level > 0) > - /* If we've thrown t to tag `exit' from within a minibuffer, we > - exit all minibuffers more deeply nested than the current > - one. */ > - { > - if (minibuf_level > minibuffer_quit_level > - && !NILP (Fminibuffer_innermost_command_loop_p (Qnil))) > - Fthrow (Qexit, Qt); > - else > - minibuffer_quit_level = 0; > - } > return val; > } > } > diff --git a/src/lisp.h b/src/lisp.h > index 7bfc69b647..4e6298a101 100644 > --- a/src/lisp.h > +++ b/src/lisp.h > @@ -4113,7 +4113,6 @@ intern_c_string (const char *str) > } > > /* Defined in eval.c. */ > -extern EMACS_INT minibuffer_quit_level; > extern Lisp_Object Vautoload_queue; > extern Lisp_Object Vrun_hooks; > extern Lisp_Object Vsignaling_function; > diff --git a/src/minibuf.c b/src/minibuf.c > index 0e7baf30dc..a4219d2a63 100644 > --- a/src/minibuf.c > +++ b/src/minibuf.c > @@ -491,8 +491,13 @@ DEFUN ("abort-minibuffers", Fabort_minibuffers, Sabort_minibuffers, 0, 0, "", > array[1] = make_fixnum (minibuf_level - minibuf_depth + 1); > if (!NILP (Fyes_or_no_p (Fformat (2, array)))) > { > - minibuffer_quit_level = minibuf_depth; > - Fthrow (Qexit, Qt); > + /* Due to the above check, the current minibuffer is in the > + most nested command loop, which means that we don't have > + to abort any extra non-minibuffer recursive edits. Thus, > + the number of recursive edits we have to abort equals the > + number of minibuffers we have to abort. */ > + CALLN (Ffuncall, intern ("minibuffer-quit-recursive-edit"), > + array[1]); > } > } > else > -- > 2.33.0 > From 387baa2b42e8220b0aac36f6f23ec3547ad0811e Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= > Date: Sun, 1 Aug 2021 02:41:37 +0200 > Subject: [PATCH] Improve documentation of exiting recursive editing > * doc/lispref/commands.texi (Recursive Editing): Mention what happens > when throwing a string or any other value to 'exit. > * src/keyboard.c (Frecursive_edit): Document throwing a function to 'exit. > --- > doc/lispref/commands.texi | 22 ++++++++++++---------- > src/keyboard.c | 18 ++++++++++++++---- > 2 files changed, 26 insertions(+), 14 deletions(-) > diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi > index ddd74d1245..3425880fec 100644 > --- a/doc/lispref/commands.texi > +++ b/doc/lispref/commands.texi > @@ -3585,17 +3585,19 @@ Recursive Editing > @cindex exit recursive editing > @cindex aborting > To invoke a recursive editing level, call the function > -@code{recursive-edit}. This function contains the command loop; it also > -contains a call to @code{catch} with tag @code{exit}, which makes it > -possible to exit the recursive editing level by throwing to @code{exit} > -(@pxref{Catch and Throw}). If you throw a @code{nil} value, then > -@code{recursive-edit} returns normally to the function that called it. > -The command @kbd{C-M-c} (@code{exit-recursive-edit}) does this. > -Throwing a @code{t} value causes @code{recursive-edit} to quit, so that > -control returns to the command loop one level up. This is called > -@dfn{aborting}, and is done by @kbd{C-]} (@code{abort-recursive-edit}). > -You can also throw a function value. In that case, > +@code{recursive-edit}. This function contains the command loop; it > +also contains a call to @code{catch} with tag @code{exit}, which makes > +it possible to exit the recursive editing level by throwing to > +@code{exit} (@pxref{Catch and Throw}). Throwing a @code{t} value > +causes @code{recursive-edit} to quit, so that control returns to the > +command loop one level up. This is called @dfn{aborting}, and is done > +by @kbd{C-]} (@code{abort-recursive-edit}). Similarly, you can throw > +a string value to make @code{recursive-edit} signal an error, printing > +this string as the message. If you throw a function, > @code{recursive-edit} will call it without arguments before returning. > +Throwing any other value, will make @code{recursive-edit} return > +normally to the function that called it. The command @kbd{C-M-c} > +(@code{exit-recursive-edit}) does this. > > Most applications should not use recursive editing, except as part of > using the minibuffer. Usually it is more convenient for the user if you > diff --git a/src/keyboard.c b/src/keyboard.c > index 63bf29a948..2d97429ade 100644 > --- a/src/keyboard.c > +++ b/src/keyboard.c > @@ -753,10 +753,20 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "", > doc: /* Invoke the editor command loop recursively. > To get out of the recursive edit, a command can throw to `exit' -- for > instance (throw \\='exit nil). > -If you throw a value other than t, `recursive-edit' returns normally > -to the function that called it. Throwing a t value causes > -`recursive-edit' to quit, so that control returns to the command loop > -one level up. > + > +The following values can be thrown to 'exit: > + > +- t causes `recursive-edit' to quit, so that control returns to the > + command loop one level up. > + > +- A string causes `recursive-edit' to signal an error, printing this > + string as the message. > + > +- A function causes `recursive-edit' to call this function without > + arguments before returning normally. > + > +- Any other value causes `recursive-edit' to return normally to the > + function that called it. > > This function is called by the editor initialization to begin editing. */) > (void) > -- > 2.33.0