]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Fix undo boundary in recursive edit (Bug#23632)
[gnu-emacs] / src / keyboard.c
index 3cddd4119dd295e49b2390aec456a8507ae01c6a..2db9aaf0297e894ce88772e51960144de8259e49 100644 (file)
@@ -7,8 +7,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -427,6 +427,14 @@ kset_system_key_syms (struct kboard *kb, Lisp_Object val)
 }
 
 \f
+static bool
+echo_keystrokes_p (void)
+{
+  return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0
+         : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0
+          : false);
+}
+
 /* Add C to the echo string, without echoing it immediately.  C can be
    a character, which is pretty-printed, or a symbol, whose name is
    printed.  */
@@ -568,7 +576,9 @@ echo_update (void)
 static void
 echo_now (void)
 {
-  if (!current_kboard->immediate_echo)
+  if (!current_kboard->immediate_echo
+      /* This test breaks calls that use `echo_now' to display the echo_prompt.
+         && echo_keystrokes_p () */)
     {
       current_kboard->immediate_echo = true;
       echo_update ();
@@ -671,6 +681,14 @@ recursive_edit_1 (void)
   specbind (Qinhibit_redisplay, Qnil);
   redisplaying_p = 0;
 
+  /* This variable stores buffers that have changed so that an undo
+     boundary can be added. specbind this so that changes in the
+     recursive edit will not result in undo boundaries in buffers
+     changed before we entered there recursive edit.
+     See Bug #23632.
+  */
+  specbind (Qundo_auto__undoably_changed_buffers, Qnil);
+
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
@@ -2270,13 +2288,6 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
     }
 }
 
-static bool
-echo_keystrokes_p (void)
-{
-  return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0
-         : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0 : false);
-}
-
 /* Read a character from the keyboard; call the redisplay if needed.  */
 /* commandflag 0 means do not autosave, but do redisplay.
    -1 means do not redisplay, but do autosave.
@@ -2526,7 +2537,7 @@ read_char (int commandflag, Lisp_Object map,
   if (KEYMAPP (map) && INTERACTIVE
       && !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event)
       /* Don't bring up a menu if we already have another event.  */
-      && NILP (Vunread_command_events)
+      && !CONSP (Vunread_command_events)
       && !detect_input_pending_run_timers (0))
     {
       c = read_char_minibuf_menu_prompt (commandflag, map);
@@ -2657,7 +2668,7 @@ read_char (int commandflag, Lisp_Object map,
       && !EQ (XCAR (prev_event), Qmenu_bar)
       && !EQ (XCAR (prev_event), Qtool_bar)
       /* Don't bring up a menu if we already have another event.  */
-      && NILP (Vunread_command_events))
+      && !CONSP (Vunread_command_events))
     {
       c = read_char_x_menu_prompt (map, prev_event, used_mouse_menu);
 
@@ -2834,7 +2845,7 @@ read_char (int commandflag, Lisp_Object map,
       if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time)
        /* We stopped being idle for this event; undo that.  This
           prevents automatic window selection (under
-          mouse_autoselect_window from acting as a real input event, for
+          mouse-autoselect-window) from acting as a real input event, for
           example banishing the mouse under mouse-avoidance-mode.  */
        timer_resume_idle ();
 
@@ -3220,33 +3231,37 @@ record_char (Lisp_Object c)
   else
     store_kbd_macro_char (c);
 
-  if (!recorded)
+  /* recent_keys should not include events from keyboard macros.  */
+  if (NILP (Vexecuting_kbd_macro))
     {
-      total_keys += total_keys < NUM_RECENT_KEYS;
-      ASET (recent_keys, recent_keys_index, c);
-      if (++recent_keys_index >= NUM_RECENT_KEYS)
-       recent_keys_index = 0;
-    }
-  else if (recorded < 0)
-    {
-      /* We need to remove one or two events from recent_keys.
-         To do this, we simply put nil at those events and move the
-        recent_keys_index backwards over those events.  Usually,
-        users will never see those nil events, as they will be
-        overwritten by the command keys entered to see recent_keys
-        (e.g. C-h l).  */
-
-      while (recorded++ < 0 && total_keys > 0)
+      if (!recorded)
        {
-         if (total_keys < NUM_RECENT_KEYS)
-           total_keys--;
-         if (--recent_keys_index < 0)
-           recent_keys_index = NUM_RECENT_KEYS - 1;
-         ASET (recent_keys, recent_keys_index, Qnil);
+         total_keys += total_keys < NUM_RECENT_KEYS;
+         ASET (recent_keys, recent_keys_index, c);
+         if (++recent_keys_index >= NUM_RECENT_KEYS)
+           recent_keys_index = 0;
+       }
+      else if (recorded < 0)
+       {
+         /* We need to remove one or two events from recent_keys.
+            To do this, we simply put nil at those events and move the
+            recent_keys_index backwards over those events.  Usually,
+            users will never see those nil events, as they will be
+            overwritten by the command keys entered to see recent_keys
+            (e.g. C-h l).  */
+
+         while (recorded++ < 0 && total_keys > 0)
+           {
+             if (total_keys < NUM_RECENT_KEYS)
+               total_keys--;
+             if (--recent_keys_index < 0)
+               recent_keys_index = NUM_RECENT_KEYS - 1;
+             ASET (recent_keys, recent_keys_index, Qnil);
+           }
        }
-    }
 
-  num_nonmacro_input_events++;
+      num_nonmacro_input_events++;
+    }
 
   /* Write c to the dribble file.  If c is a lispy event, write
      the event's symbol to the dribble file, in <brackets>.  Bleaugh.
@@ -7142,9 +7157,6 @@ struct user_signal_info
 /* List of user signals.  */
 static struct user_signal_info *user_signals = NULL;
 
-/* Function called when handling user signals.  */
-void (*handle_user_signal_hook) (int);
-
 void
 add_user_signal (int sig, const char *name)
 {
@@ -7193,8 +7205,6 @@ handle_user_signal (int sig)
           }
 
        p->npending++;
-       if (handle_user_signal_hook)
-         (*handle_user_signal_hook) (sig);
 #ifdef USABLE_SIGIO
        if (interrupt_input)
          handle_input_available_signal (sig);
@@ -8891,10 +8901,16 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
             of echoing, so that it serves as a prompt for the next
             character.  */
          kset_echo_prompt (current_kboard, prompt);
+          /* FIXME: This use of echo_now doesn't look quite right and is ugly
+             since it forces us to fiddle with current_kboard->immediate_echo
+             before and after.  */
          current_kboard->immediate_echo = false;
          echo_now ();
+          if (!echo_keystrokes_p ())
+           current_kboard->immediate_echo = false;
        }
-      else if (cursor_in_echo_area
+      else if (cursor_in_echo_area /* FIXME: Not sure why we test this here,
+                                      maybe we should just drop this test.  */
               && echo_keystrokes_p ())
        /* This doesn't put in a dash if the echo buffer is empty, so
           you don't always see a dash hanging out in the minibuffer.  */
@@ -9870,7 +9886,7 @@ clear_input_pending (void)
 bool
 requeued_events_pending_p (void)
 {
-  return (!NILP (Vunread_command_events));
+  return (CONSP (Vunread_command_events));
 }
 
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 1, 0,
@@ -9881,7 +9897,7 @@ if there is a doubt, the value is t.
 If CHECK-TIMERS is non-nil, timers that are ready to run will do so.  */)
   (Lisp_Object check_timers)
 {
-  if (!NILP (Vunread_command_events)
+  if (CONSP (Vunread_command_events)
       || !NILP (Vunread_post_input_method_events)
       || !NILP (Vunread_input_method_events))
     return (Qt);
@@ -10307,7 +10323,7 @@ handle_interrupt (bool in_signal_handler)
        {
          write_stdout ("Auto-save? (y or n) ");
          c = read_stdin ();
-         if ((c & 040) == 'Y')
+         if (c == 'y' || c == 'Y')
            {
              Fdo_auto_save (Qt, Qnil);
 #ifdef MSDOS
@@ -10339,7 +10355,7 @@ handle_interrupt (bool in_signal_handler)
       write_stdout ("Abort (and dump core)? (y or n) ");
 #endif
       c = read_stdin ();
-      if ((c & ~040) == 'Y')
+      if (c == 'y' || c == 'Y')
        emacs_abort ();
       while (c != '\n')
        c = read_stdin ();
@@ -10948,6 +10964,8 @@ syms_of_keyboard (void)
   DEFSYM (Qpost_command_hook, "post-command-hook");
 
   DEFSYM (Qundo_auto__add_boundary, "undo-auto--add-boundary");
+  DEFSYM (Qundo_auto__undoably_changed_buffers,
+          "undo-auto--undoably-changed-buffers");
 
   DEFSYM (Qdeferred_action_function, "deferred-action-function");
   DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook");
@@ -11374,7 +11392,7 @@ See Info node `(elisp)Multiple Terminals'.  */);
 
   DEFVAR_BOOL ("cannot-suspend", cannot_suspend,
               doc: /* Non-nil means to always spawn a subshell instead of suspending.
-(Even if the operating system has support for stopping a process.)  */);
+\(Even if the operating system has support for stopping a process.)  */);
   cannot_suspend = false;
 
   DEFVAR_BOOL ("menu-prompting", menu_prompting,
@@ -11588,7 +11606,7 @@ immediately after running `post-command-hook'.  */);
   DEFVAR_LISP ("input-method-function", Vinput_method_function,
               doc: /* If non-nil, the function that implements the current input method.
 It's called with one argument, a printing character that was just read.
-(That means a character with code 040...0176.)
+\(That means a character with code 040...0176.)
 Typically this function uses `read-event' to read additional events.
 When it does so, it should first bind `input-method-function' to nil
 so it will not be called recursively.
@@ -11621,10 +11639,10 @@ It's called with one argument, the help string to display.  */);
   DEFVAR_LISP ("disable-point-adjustment", Vdisable_point_adjustment,
               doc: /* If non-nil, suppress point adjustment after executing a command.
 
-After a command is executed, if point is moved into a region that has
-special properties (e.g. composition, display), we adjust point to
-the boundary of the region.  But, when a command sets this variable to
-non-nil, we suppress the point adjustment.
+After a command is executed, if point moved into a region that has
+special properties (e.g. composition, display), Emacs adjusts point to
+the boundary of the region.  But when a command leaves this variable at
+a non-nil value (e.g., with a setq), this point adjustment is suppressed.
 
 This variable is set to nil before reading a command, and is checked
 just after executing the command.  */);
@@ -11632,11 +11650,11 @@ just after executing the command.  */);
 
   DEFVAR_LISP ("global-disable-point-adjustment",
               Vglobal_disable_point_adjustment,
-              doc: /* If non-nil, always suppress point adjustment.
+              doc: /* If non-nil, always suppress point adjustments.
 
-The default value is nil, in which case, point adjustment are
-suppressed only after special commands that set
-`disable-point-adjustment' (which see) to non-nil.  */);
+The default value is nil, in which case point adjustments are
+suppressed only after special commands that leave
+`disable-point-adjustment' (which see) at a non-nil value.  */);
   Vglobal_disable_point_adjustment = Qnil;
 
   DEFVAR_LISP ("minibuffer-message-timeout", Vminibuffer_message_timeout,