emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Stop frames stealing eachothers' minibuffers!


From: Alan Mackenzie
Subject: Re: Stop frames stealing eachothers' minibuffers!
Date: Sat, 28 Nov 2020 15:35:49 +0000

> Hello, Gregory and Martin.

On Sat, Nov 28, 2020 at 10:45:34 +0000, Alan Mackenzie wrote:

> On Fri, Nov 27, 2020 at 07:33:04 +0000, Gregory Heytings wrote:

> [ .... ]

> >   | Emacs 21-27 | Emacs 28 with (setq m-f-s-f t) | Emacs 28 with (setq 
> > m-f-s-f nil)
> > A | MB1 on F1   | MB1 on F2                      | MB1 on F1
> > B | MB1+2 on F2 | MB1+2 on F2                    | MB1 on F1, MB2 on F2 [1]

> > A: type C-x C-f on frame F1, switch to frame F2
> > B: type C-x C-f on frame F1, switch to frame F2, type M-:

> > [1] There is also a severe regression in this case.  Type C-x C-f on frame 
> > F1, switch to frame F2, type M-:.  "Find file" is still visible in the 
> > miniwindow on frame F1; switch to frame F1.

> > Experiment 1: Type the name of a file and RET.  You'll get the error 
> > message "End of file during parsing", and MB2 on frame F2 will be left. 
> > MB1 is now unuseable, and impossible to leave, it will stay on F1 whatever 
> > you do.

> > Experiment 2: Type C-g.  MB2 on frame F2 will be left, and "Find file" 
> > will stay in MB1 on frame F1.  However you cannot use it anymore, the 
> > keymap of MB1 is now minibuffer-inactive-mode-map.  And like in experiment 
> > 1, you cannot leave it.

> The abstract cause of this situation would appear to be using F1's
> minibuffer while a more deeply nested minibuffer is still active.  It is
> a violation of the "recursive" nature of these buffers.

> I think a solution would be to put F1's minibuffer into
> minibuffer-inactive-mode until the recursive MB in F2 has terminated.

> What do you think of this?

Here's a trial implementation, which doesn't quite put F1's MB into
minibuffer-inactive-mode, but sets its local keymap to the mode's
keymap.



diff --git a/src/minibuf.c b/src/minibuf.c
index fc3fd92a88..58e72bc4a4 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -63,6 +63,8 @@ static Lisp_Object minibuf_prompt;
 
 static ptrdiff_t minibuf_prompt_width;
 
+static Lisp_Object nth_minibuffer (EMACS_INT depth);
+
 
 static bool
 minibuf_follows_frame (void)
@@ -90,7 +92,7 @@ choose_minibuf_frame (void)
       minibuf_window = sf->minibuffer_window;
       /* If we've still got another minibuffer open, use its mini-window
          instead.  */
-      if (minibuf_level && !minibuf_follows_frame ())
+      if (minibuf_level > 1 && !minibuf_follows_frame ())
         {
           Lisp_Object buffer = get_minibuffer (minibuf_level);
           Lisp_Object tail, frame;
@@ -411,6 +413,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, 
Lisp_Object prompt,
   Lisp_Object val;
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object mini_frame, ambient_dir, minibuffer, input_method;
+  Lisp_Object calling_frame = selected_frame;
   Lisp_Object enable_multibyte;
   EMACS_INT pos = 0;
   /* String to add to the history.  */
@@ -532,7 +535,9 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, 
Lisp_Object prompt,
   minibuf_save_list
     = Fcons (Voverriding_local_map,
             Fcons (minibuf_window,
-                   minibuf_save_list));
+                    Fcons (BVAR (XBUFFER (nth_minibuffer (minibuf_level - 1)),
+                                 keymap),
+                           minibuf_save_list)));
   minibuf_save_list
     = Fcons (minibuf_prompt,
             Fcons (make_fixnum (minibuf_prompt_width),
@@ -727,8 +732,26 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, 
Lisp_Object prompt,
   /* Don't allow the user to undo past this point.  */
   bset_undo_list (current_buffer, Qnil);
 
+  /* Prevent the user manipulating outer levels of recursive minibuffers.  */
+  if (minibuf_level > 1)
+    {
+      Lisp_Object inactive_map;
+      if ((inactive_map =
+           find_symbol_value (intern ("minibuffer-inactive-mode-map")))
+          != Qunbound)
+        bset_keymap (XBUFFER (nth_minibuffer (minibuf_level - 1)),
+                     inactive_map);
+    }
+
   recursive_edit_1 ();
 
+  /* We've exited the recursive edit without an error, so switch the frame
+     back to the calling frame.  */
+  if (!EQ (selected_frame, calling_frame)
+      && FRAMEP (calling_frame)
+      && FRAME_LIVE_P (XFRAME (calling_frame)))
+    do_switch_frame (calling_frame, 1, 0, Qnil);
+
   /* If cursor is on the minibuffer line,
      show the user we have exited by putting it in column 0.  */
   if (XWINDOW (minibuf_window)->cursor.vpos >= 0
@@ -790,6 +813,14 @@ is_minibuffer (EMACS_INT depth, Lisp_Object buf)
     && EQ (Fcar (tail), buf);
 }
 
+/* Return the DEPTHth minibuffer, or nil if such does not yet exist.  */
+static Lisp_Object
+nth_minibuffer (EMACS_INT depth)
+{
+  Lisp_Object tail = Fnthcdr (make_fixnum (depth), Vminibuffer_list);
+  return XCAR (tail);
+}
+
 /* Return a buffer to be used as the minibuffer at depth `depth'.
    depth = 0 is the lowest allowed argument, and that is the value
    used for nonrecursive minibuffer invocations.  */
@@ -852,6 +883,7 @@ read_minibuf_unwind (void)
   Lisp_Object old_deactivate_mark;
   Lisp_Object window;
   Lisp_Object future_mini_window;
+  Lisp_Object map;
 
   /* If this was a recursive minibuffer,
      tie the minibuffer window back to the outer level minibuffer buffer.  */
@@ -888,6 +920,8 @@ read_minibuf_unwind (void)
 #endif
   future_mini_window = Fcar (minibuf_save_list);
   minibuf_save_list = Fcdr (minibuf_save_list);
+  map = Fcar (minibuf_save_list);
+  minibuf_save_list = Fcdr (minibuf_save_list);
 
   /* Erase the minibuffer we were using at this level.  */
   {
@@ -901,6 +935,10 @@ read_minibuf_unwind (void)
     unbind_to (count, Qnil);
   }
 
+  /* Restore the keymap of any outer level recursive minibuffer. */
+  if (minibuf_level > 0)
+    bset_keymap (XBUFFER (nth_minibuffer (minibuf_level)), map);
+
   /* When we get to the outmost level, make sure we resize the
      mini-window back to its normal size.  */
   if (minibuf_level == 0



-- 
Alan Mackenzie (Nuremberg, Germany).



reply via email to

[Prev in Thread] Current Thread [Next in Thread]