Subject: Re: [External] : bug#47150: 28.0.50; Incorrect major-mode in minibuffer

From: Alan Mackenzie <[email-masked]>
Date: Mon, 19 Apr 2021 17:30:30 +0000

Hello, everybody.

On Mon, Apr 19, 2021 at 09:33:04 +0000, Alan Mackenzie wrote:

[ .... ]

> I posted a patch for this yesterday.  In the documentation bit, I
> strongly advised against using minibuffer-mode-hook, instead directing
> users to minibuffer-setup-hook and minibuffer-exit-hook.  Was this the
> right thing to write?

Apologies.  That post didn't make it out, after all.  Here is the patch I
meant to send.  I invite Sheng, in particular, to report how well it
fixes the bug.  Thanks!

diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi
index 1eba7074f7..6f2935f1f6 100644
--- a/doc/emacs/mini.texi
+++ b/doc/emacs/mini.texi
@@ -247,6 +247,9 @@ Minibuffer Edit
 to show the current recursion depth in the minibuffer prompt
 on recursive use of the minibuffer.
 
+  When active, the minibuffer is in @code{minibuffer-mode}.  This is
+an internal Emacs mode without any features for the user.
+
 @findex minibuffer-inactive-mode
   When not active, the minibuffer is in @code{minibuffer-inactive-mode},
 and clicking @kbd{mouse-1} there shows the @file{*Messages*} buffer.
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index d16409d6c8..edb46bbefe 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -97,6 +97,13 @@ Intro to Minibuffers
 minibuffer local maps.  @xref{Completion Commands}, for the minibuffer
 local maps for completion.
 
+@cindex active minibuffer
+  An active minibuffer has major mode @code{minibuffer-mode}.  This is
+an Emacs internal mode, and there is never any point in calling it or
+otherwise trying to manipulate it.  Rather than using
+@code{minibuffer-mode-hook}, you should use
+@code{minibuffer-setup-hook} (@pxref{Minibuffer Misc}).
+
 @cindex inactive minibuffer
   When a minibuffer is inactive, its major mode is
 @code{minibuffer-inactive-mode}, with keymap
diff --git a/etc/NEWS b/etc/NEWS
index b641e8d95f..3e5767c953 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2392,6 +2392,10 @@ This affects the suffix specified by completion 'annotation-function'.
 ** 'set-process-buffer' now updates the process mark.
 The mark will be set to point to the end of the new buffer.
 
++++
+** An active minibuffer now has major mode 'minibuffer-mode', not the
+erroneous 'minibuffer-inactive-mode' it formerly had.
+
 +++
 ** Some properties from completion tables are now preserved.
 If 'minibuffer-allow-text-properties' is non-nil, doing completion
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index c900b0d7ce..1a719a12cc 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2474,6 +2474,16 @@ minibuffer-inactive-mode
   "Major mode to use in the minibuffer when it is not active.
 This is only used when the minibuffer area has no active minibuffer.")
 
+(define-derived-mode minibuffer-mode nil "Minibuffer"
+  "Major mode used only in active minibuffers.
+This mode is used internally, and should not be set by user code
+in any way, although it may be tested by such code.  Use
+`minibuffer-setup-hook' and `minibuffer-exit-hook' rather than
+the mode hook of this mode."
+  :syntax-table nil
+  :abbrev-table nil
+  :interactive nil)
+
 ;;; Completion tables.
 
 (defun minibuffer--double-dollars (str)
diff --git a/src/minibuf.c b/src/minibuf.c
index a3c1b99bf3..439addc9a9 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -567,7 +567,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
      in previous recursive minibuffer, but was not set explicitly
      to t for this invocation, so set it to nil in this minibuffer.
      Save the old value now, before we change it.  */
-  specbind (intern ("minibuffer-completing-file-name"),
+  specbind (Qminibuffer_completing_file_name,
 	    Vminibuffer_completing_file_name);
   if (EQ (Vminibuffer_completing_file_name, Qlambda))
     Vminibuffer_completing_file_name = Qnil;
@@ -920,13 +920,13 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
 	      && !EQ (XWINDOW (XFRAME (calling_frame)->minibuffer_window)
 		      ->frame,
 		      calling_frame))))
-    call2 (intern ("select-frame-set-input-focus"), calling_frame, Qnil);
+    call2 (Qselect_frame_set_input_focus, calling_frame, Qnil);
 
   /* Add the value to the appropriate history list, if any.  This is
      done after the previous buffer has been made current again, in
      case the history variable is buffer-local.  */
   if (! (NILP (Vhistory_add_new_input) || NILP (histstring)))
-    call2 (intern ("add-to-history"), histvar, histstring);
+    call2 (Qadd_to_history, histvar, histstring);
 
   /* If Lisp form desired instead of string, parse it.  */
   if (expflag)
@@ -965,13 +965,13 @@ set_minibuffer_mode (Lisp_Object buf, EMACS_INT depth)
   Fset_buffer (buf);
   if (depth > 0)
     {
-      if (!NILP (Ffboundp (intern ("fundamental-mode"))))
-	call0 (intern ("fundamental-mode"));
+      if (!NILP (Ffboundp (Qminibuffer_mode)))
+	call0 (Qminibuffer_mode);
     }
   else
     {
-      if (!NILP (Ffboundp (intern ("minibuffer-inactive-mode"))))
-	call0 (intern ("minibuffer-inactive-mode"));
+      if (!NILP (Ffboundp (Qminibuffer_inactive_mode)))
+	call0 (Qminibuffer_inactive_mode);
       else
 	Fkill_all_local_variables ();
     }
@@ -1163,7 +1163,7 @@ read_minibuf_unwind (void)
      dead, we may keep displaying this buffer (tho it's inactive), so reset it,
      to make sure we don't leave around bindings and stuff which only
      made sense during the read_minibuf invocation.  */
-  call0 (intern ("minibuffer-inactive-mode"));
+  call0 (Qminibuffer_inactive_mode);
 
   /* We've exited the recursive edit, so switch the current windows
      away from the expired minibuffer window, both in the current
@@ -2332,6 +2332,12 @@ syms_of_minibuf (void)
   /* A frame parameter.  */
   DEFSYM (Qminibuffer_exit, "minibuffer-exit");
 
+  DEFSYM (Qminibuffer_mode, "minibuffer-mode");
+  DEFSYM (Qminibuffer_inactive_mode, "minibuffer-inactive-mode");
+  DEFSYM (Qminibuffer_completing_file_name, "minibuffer-completing-file-name");
+  DEFSYM (Qselect_frame_set_input_focus, "select-frame-set-input-focus");
+  DEFSYM (Qadd_to_history, "add-to-history");
+
   DEFVAR_LISP ("read-expression-history", Vread_expression_history,
 	       doc: /* A history list for arguments that are Lisp expressions to evaluate.
 For example, `eval-expression' uses this.  */);

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).