Subject: Re: bug#6758: 23.2; xterm.el: please provide an option to not discard input in terminal-init-xterm

From: Stefan Monnier <[email-masked]>
Date: Sat, 11 Sep 2010 16:59:29 +0200

> Any thoughts on this patch?
> I've found further problems with doing aynchronous terminal queries:
> minibuffer prompts get aborted by the xterm response.  For example,
> when opening up a large file:

> 1) Emacs loads and sends "\e[>0c"
> 2) Emacs prints the "File x is large (123MB), really open? (y or n)" prompt
> 3) Xterm sends the "\e[>0;253;0c" response, aborting the prompt

You can try the patch below (may require manual application, it's made
against a non-vanilla tree) to see if it fixes your problem,

        Stefan

=== modified file 'lisp/subr.el'
--- lisp/subr.el	2010-09-11 09:14:23 +0000
+++ lisp/subr.el	2010-09-11 14:57:41 +0000
@@ -3680,6 +3680,52 @@
   buffer)

+(defun y-or-n-p (prompt)
+  "Ask user a \"y or n\" question.  Return t if answer is \"y\".
+The argument PROMPT is the string to display to ask the question.
+It should end in a space; `y-or-n-p' adds `(y or n) ' to it.
+No confirmation of the answer is requested; a single character is enough.
+Also accepts Space to mean yes, or Delete to mean no.  \(Actually, it uses
+the bindings in `query-replace-map'; see the documentation of that variable
+for more information.  In this case, the useful bindings are `act', `skip',
+`recenter', and `quit'.\)
+
+Under a windowing system a dialog box will be used if `last-nonmenu-event'
+is nil and `use-dialog-box' is non-nil."
+  (let ((answer 'none)
+        (xprompt (setq prompt (propertize (concat prompt "(y or n) ")
+                                          'face 'minibuffer-prompt))))
+    (if (and (display-popup-menus-p)
+             (listp last-nonmenu-event)
+             use-dialog-box)
+        (progn
+          (setq answer
+                (x-popup-dialog t `(,prompt ("yes" . t) ("No" . nil)))))
+      (while
+          (progn
+            (when minibuffer-auto-raise
+              (raise-frame (window-frame (minibuffer-window))))
+            (let* ((key
+                    (let ((cursor-in-echo-area t))
+                      (read-key xprompt))))
+              (setq answer (lookup-key query-replace-map (vector key) t))
+              (case answer
+                ((skip act) nil)
+                (recenter (recenter) t)
+                ((exit-prefix quit) (signal 'quit nil) t)
+                (t t))))
+        (ding)
+        (discard-input)
+        (setq xprompt
+              (if (eq answer 'recenter) prompt
+                (propertize (concat "Please answer y or n.  " prompt)
+                            'face 'minibuffer-prompt))))
+
+      (let ((ret (eq answer 'act)))
+        (unless noninteractive
+          (message "%s %s" prompt (if ret "y" "n")))
+        ret))))
+
 ;; (defun get-doc-string (pos &optional unibyte definition)
 ;;   (let ((file (or (car-safe pos) internal-doc-file-name))
 ;; 	(position (or (cdr-safe pos) pos))

=== modified file 'src/fileio.c'
--- src/fileio.c	2010-08-10 10:46:59 +0000
+++ src/fileio.c	2010-09-11 14:22:33 +0000
@@ -1842,7 +1842,7 @@
       tem = format2 ("File %s already exists; %s anyway? ",
 		     absname, build_string (querystring));
       if (quick)
-	tem = Fy_or_n_p (tem);
+	tem = call1 (intern ("y-or-n-p"), tem);
       else
 	tem = do_yes_or_no_p (tem);
       UNGCPRO;

=== modified file 'src/fns.c'
--- src/fns.c	2010-08-14 22:35:37 +0000
+++ src/fns.c	2010-09-11 14:10:27 +0000
@@ -2437,146 +2437,6 @@
   return sequence;
 }
 
-/* Anything that calls this function must protect from GC!  */
-
-DEFUN ("y-or-n-p", Fy_or_n_p, Sy_or_n_p, 1, 1, 0,
-       doc: /* Ask user a "y or n" question.  Return t if answer is "y".
-Takes one argument, which is the string to display to ask the question.
-It should end in a space; `y-or-n-p' adds `(y or n) ' to it.
-No confirmation of the answer is requested; a single character is enough.
-Also accepts Space to mean yes, or Delete to mean no.  \(Actually, it uses
-the bindings in `query-replace-map'; see the documentation of that variable
-for more information.  In this case, the useful bindings are `act', `skip',
-`recenter', and `quit'.\)
-
-Under a windowing system a dialog box will be used if `last-nonmenu-event'
-is nil and `use-dialog-box' is non-nil.  */)
-  (Lisp_Object prompt)
-{
-  register Lisp_Object obj, key, def, map;
-  register int answer;
-  Lisp_Object xprompt;
-  Lisp_Object args[2];
-  struct gcpro gcpro1, gcpro2;
-  int count = SPECPDL_INDEX ();
-
-  specbind (Qcursor_in_echo_area, Qt);
-
-  map = Fsymbol_value (intern ("query-replace-map"));
-
-  CHECK_STRING (prompt);
-  xprompt = prompt;
-  GCPRO2 (prompt, xprompt);
-
-#ifdef HAVE_WINDOW_SYSTEM
-  if (display_hourglass_p)
-    cancel_hourglass ();
-#endif
-
-  while (1)
-    {
-
-#ifdef HAVE_MENUS
-      if (FRAME_WINDOW_P (SELECTED_FRAME ())
-          && (NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
-	  && use_dialog_box
-	  && have_menus_p ())
-	{
-	  Lisp_Object pane, menu;
-	  redisplay_preserve_echo_area (3);
-	  pane = Fcons (Fcons (build_string ("Yes"), Qt),
-			Fcons (Fcons (build_string ("No"), Qnil),
-			       Qnil));
-	  menu = Fcons (prompt, pane);
-	  obj = Fx_popup_dialog (Qt, menu, Qnil);
-	  answer = !NILP (obj);
-	  break;
-	}
-#endif /* HAVE_MENUS */
-      cursor_in_echo_area = 1;
-      choose_minibuf_frame ();
-
-      {
-	Lisp_Object pargs[3];
-
-	/* Colorize prompt according to `minibuffer-prompt' face.  */
-	pargs[0] = build_string ("%s(y or n) ");
-	pargs[1] = intern ("face");
-	pargs[2] = intern ("minibuffer-prompt");
-	args[0] = Fpropertize (3, pargs);
-	args[1] = xprompt;
-	Fmessage (2, args);
-      }
-
-      if (minibuffer_auto_raise)
-	{
-	  Lisp_Object mini_frame;
-
-	  mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
-
-	  Fraise_frame (mini_frame);
-	}
-
-      temporarily_switch_to_single_kboard (SELECTED_FRAME ());
-      obj = read_filtered_event (1, 0, 0, 0, Qnil);
-      cursor_in_echo_area = 0;
-      /* If we need to quit, quit with cursor_in_echo_area = 0.  */
-      QUIT;
-
-      key = Fmake_vector (make_number (1), obj);
-      def = Flookup_key (map, key, Qt);
-
-      if (EQ (def, intern ("skip")))
-	{
-	  answer = 0;
-	  break;
-	}
-      else if (EQ (def, intern ("act")))
-	{
-	  answer = 1;
-	  break;
-	}
-      else if (EQ (def, intern ("recenter")))
-	{
-	  Frecenter (Qnil);
-	  xprompt = prompt;
-	  continue;
-	}
-      else if (EQ (def, intern ("quit")))
-	Vquit_flag = Qt;
-      /* We want to exit this command for exit-prefix,
-	 and this is the only way to do it.  */
-      else if (EQ (def, intern ("exit-prefix")))
-	Vquit_flag = Qt;
-
-      QUIT;
-
-      /* If we don't clear this, then the next call to read_char will
-	 return quit_char again, and we'll enter an infinite loop.  */
-      Vquit_flag = Qnil;
-
-      Fding (Qnil);
-      Fdiscard_input ();
-      if (EQ (xprompt, prompt))
-	{
-	  args[0] = build_string ("Please answer y or n.  ");
-	  args[1] = prompt;
-	  xprompt = Fconcat (2, args);
-	}
-    }
-  UNGCPRO;
-
-  if (! noninteractive)
-    {
-      cursor_in_echo_area = -1;
-      message_with_string (answer ? "%s(y or n) y" : "%s(y or n) n",
-			   xprompt, 0);
-    }
-
-  unbind_to (count, Qnil);
-  return answer ? Qt : Qnil;
-}
-
 /* This is how C code calls `yes-or-no-p' and allows the user
    to redefined it.
 
@@ -5057,7 +4917,6 @@
   defsubr (&Smapcar);
   defsubr (&Smapc);
   defsubr (&Smapconcat);
-  defsubr (&Sy_or_n_p);
   defsubr (&Syes_or_no_p);
   defsubr (&Sload_average);
   defsubr (&Sfeaturep);

=== modified file 'src/lisp.h'
--- src/lisp.h	2010-09-10 23:24:48 +0000
+++ src/lisp.h	2010-09-11 14:09:41 +0000
@@ -2586,7 +2586,6 @@
 EXFUN (Fnconc, MANY);
 EXFUN (Fmapcar, 2);
 EXFUN (Fmapconcat, 3);
-EXFUN (Fy_or_n_p, 1);
 extern Lisp_Object do_yes_or_no_p (Lisp_Object);
 EXFUN (Frequire, 3);
 EXFUN (Fprovide, 2);