]> code.delx.au - gnu-emacs/blobdiff - src/undo.c
Remove now-inaccurate bytecode comments
[gnu-emacs] / src / undo.c
index 7286d40b2e515332a2e923e8677d24668a93278e..be5b27020540a882287ca5a128ee82392a7e065b 100644 (file)
@@ -1,13 +1,13 @@
 /* undo handling for GNU Emacs.
-   Copyright (C) 1990, 1993-1994, 2000-2014 Free Software Foundation,
+   Copyright (C) 1990, 1993-1994, 2000-2016 Free Software Foundation,
    Inc.
 
 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
@@ -21,24 +21,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #include "lisp.h"
-#include "character.h"
 #include "buffer.h"
-#include "commands.h"
-#include "window.h"
-
-/* Last buffer for which undo information was recorded.  */
-/* BEWARE: This is not traced by the GC, so never dereference it!  */
-static struct buffer *last_undo_buffer;
-
-/* Position of point last time we inserted a boundary.  */
-static struct buffer *last_boundary_buffer;
-static ptrdiff_t last_boundary_position;
-
-Lisp_Object Qinhibit_read_only;
-
-/* Marker for function call undo list elements.  */
-
-Lisp_Object Qapply;
+#include "keyboard.h"
 
 /* The first time a command records something for undo.
    it also allocates the undo-boundary object
@@ -49,64 +33,40 @@ static Lisp_Object pending_boundary;
 
 /* Record point as it was at beginning of this command (if necessary)
    and prepare the undo info for recording a change.
+   Prepare the undo info for recording a change. */
+static void
+prepare_record (void)
+{
+  /* Allocate a cons cell to be the undo boundary after this command.  */
+  if (NILP (pending_boundary))
+    pending_boundary = Fcons (Qnil, Qnil);
+
+  if (MODIFF <= SAVE_MODIFF)
+    record_first_change ();
+}
+
+/* Record point as it was at beginning of this command.
    PT is the position of point that will naturally occur as a result of the
    undo record that will be added just after this command terminates.  */
-
 static void
 record_point (ptrdiff_t pt)
 {
-  bool at_boundary;
-
   /* Don't record position of pt when undo_inhibit_record_point holds.  */
   if (undo_inhibit_record_point)
     return;
 
-  /* Allocate a cons cell to be the undo boundary after this command.  */
-  if (NILP (pending_boundary))
-    pending_boundary = Fcons (Qnil, Qnil);
-
-  if ((current_buffer != last_undo_buffer)
-      /* Don't call Fundo_boundary for the first change.  Otherwise we
-        risk overwriting last_boundary_position in Fundo_boundary with
-        PT of the current buffer and as a consequence not insert an
-        undo boundary because last_boundary_position will equal pt in
-        the test at the end of the present function (Bug#731).  */
-      && (MODIFF > SAVE_MODIFF))
-    Fundo_boundary ();
-  last_undo_buffer = current_buffer;
-
-  if (CONSP (BVAR (current_buffer, undo_list)))
-    {
-      /* Set AT_BOUNDARY only when we have nothing other than
-         marker adjustment before undo boundary.  */
-
-      Lisp_Object tail = BVAR (current_buffer, undo_list), elt;
+  bool at_boundary;
 
-      while (1)
-       {
-         if (NILP (tail))
-           elt = Qnil;
-         else
-           elt = XCAR (tail);
-         if (NILP (elt) || ! (CONSP (elt) && MARKERP (XCAR (elt))))
-           break;
-         tail = XCDR (tail);
-       }
-      at_boundary = NILP (elt);
-    }
-  else
-    at_boundary = 1;
+  at_boundary = ! CONSP (BVAR (current_buffer, undo_list))
+                || NILP (XCAR (BVAR (current_buffer, undo_list)));
 
-  if (MODIFF <= SAVE_MODIFF)
-    record_first_change ();
+  prepare_record ();
 
   /* If we are just after an undo boundary, and
      point wasn't at start of deleted range, record where it was.  */
-  if (at_boundary
-      && current_buffer == last_boundary_buffer
-      && last_boundary_position != pt)
+  if (at_boundary)
     bset_undo_list (current_buffer,
-                   Fcons (make_number (last_boundary_position),
+                   Fcons (make_number (pt),
                           BVAR (current_buffer, undo_list)));
 }
 
@@ -123,7 +83,7 @@ record_insert (ptrdiff_t beg, ptrdiff_t length)
   if (EQ (BVAR (current_buffer, undo_list), Qt))
     return;
 
-  record_point (beg);
+  prepare_record ();
 
   /* If this is following another insertion and consecutive with it
      in the buffer, combine the two.  */
@@ -147,56 +107,86 @@ record_insert (ptrdiff_t beg, ptrdiff_t length)
                  Fcons (Fcons (lbeg, lend), BVAR (current_buffer, undo_list)));
 }
 
-/* Record that a deletion is about to take place,
-   of the characters in STRING, at location BEG.  */
+/* Record the fact that markers in the region of FROM, TO are about to
+   be adjusted.  This is done only when a marker points within text
+   being deleted, because that's the only case where an automatic
+   marker adjustment won't be inverted automatically by undoing the
+   buffer modification.  */
 
+static void
+record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
+{
+  Lisp_Object marker;
+  register struct Lisp_Marker *m;
+  register ptrdiff_t charpos, adjustment;
+
+  /* Allocate a cons cell to be the undo boundary after this command.  */
+  if (NILP (pending_boundary))
+    pending_boundary = Fcons (Qnil, Qnil);
+
+  for (m = BUF_MARKERS (current_buffer); m; m = m->next)
+    {
+      charpos = m->charpos;
+      eassert (charpos <= Z);
+
+      if (from <= charpos && charpos <= to)
+        {
+          /* insertion_type nil markers will end up at the beginning of
+             the re-inserted text after undoing a deletion, and must be
+             adjusted to move them to the correct place.
+
+             insertion_type t markers will automatically move forward
+             upon re-inserting the deleted text, so we have to arrange
+             for them to move backward to the correct position.  */
+          adjustment = (m->insertion_type ? to : from) - charpos;
+
+          if (adjustment)
+            {
+              XSETMISC (marker, m);
+              bset_undo_list
+                (current_buffer,
+                 Fcons (Fcons (marker, make_number (adjustment)),
+                        BVAR (current_buffer, undo_list)));
+            }
+        }
+    }
+}
+
+/* Record that a deletion is about to take place, of the characters in
+   STRING, at location BEG.  Optionally record adjustments for markers
+   in the region STRING occupies in the current buffer.  */
 void
-record_delete (ptrdiff_t beg, Lisp_Object string)
+record_delete (ptrdiff_t beg, Lisp_Object string, bool record_markers)
 {
   Lisp_Object sbeg;
 
   if (EQ (BVAR (current_buffer, undo_list), Qt))
     return;
 
+  if (point_before_last_command_or_undo != beg
+      && buffer_before_last_command_or_undo == current_buffer)
+    record_point (point_before_last_command_or_undo);
+
   if (PT == beg + SCHARS (string))
     {
       XSETINT (sbeg, -beg);
-      record_point (PT);
+      prepare_record ();
     }
   else
     {
       XSETFASTINT (sbeg, beg);
-      record_point (beg);
+      prepare_record ();
     }
 
-  bset_undo_list
-    (current_buffer,
-     Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list)));
-}
-
-/* Record the fact that MARKER is about to be adjusted by ADJUSTMENT.
-   This is done only when a marker points within text being deleted,
-   because that's the only case where an automatic marker adjustment
-   won't be inverted automatically by undoing the buffer modification.  */
-
-void
-record_marker_adjustment (Lisp_Object marker, ptrdiff_t adjustment)
-{
-  if (EQ (BVAR (current_buffer, undo_list), Qt))
-    return;
-
-  /* Allocate a cons cell to be the undo boundary after this command.  */
-  if (NILP (pending_boundary))
-    pending_boundary = Fcons (Qnil, Qnil);
-
-  if (current_buffer != last_undo_buffer)
-    Fundo_boundary ();
-  last_undo_buffer = current_buffer;
+  /* primitive-undo assumes marker adjustments are recorded
+     immediately before the deletion is recorded.  See bug 16818
+     discussion.  */
+  if (record_markers)
+    record_marker_adjustments (beg, beg + SCHARS (string));
 
   bset_undo_list
     (current_buffer,
-     Fcons (Fcons (marker, make_number (adjustment)),
-           BVAR (current_buffer, undo_list)));
+     Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list)));
 }
 
 /* Record that a replacement is about to take place,
@@ -206,7 +196,7 @@ record_marker_adjustment (Lisp_Object marker, ptrdiff_t adjustment)
 void
 record_change (ptrdiff_t beg, ptrdiff_t length)
 {
-  record_delete (beg, make_buffer_string (beg, beg + length, 1));
+  record_delete (beg, make_buffer_string (beg, beg + length, true), false);
   record_insert (beg, length);
 }
 \f
@@ -222,10 +212,6 @@ record_first_change (void)
   if (EQ (BVAR (current_buffer, undo_list), Qt))
     return;
 
-  if (current_buffer != last_undo_buffer)
-    Fundo_boundary ();
-  last_undo_buffer = current_buffer;
-
   if (base_buffer->base_buffer)
     base_buffer = base_buffer->base_buffer;
 
@@ -243,8 +229,7 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
                        Lisp_Object buffer)
 {
   Lisp_Object lbeg, lend, entry;
-  struct buffer *obuf = current_buffer, *buf = XBUFFER (buffer);
-  bool boundary = 0;
+  struct buffer *buf = XBUFFER (buffer);
 
   if (EQ (BVAR (buf, undo_list), Qt))
     return;
@@ -253,16 +238,6 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
   if (NILP (pending_boundary))
     pending_boundary = Fcons (Qnil, Qnil);
 
-  if (buf != last_undo_buffer)
-    boundary = 1;
-  last_undo_buffer = buf;
-
-  /* Switch temporarily to the buffer that was changed.  */
-  current_buffer = buf;
-
-  if (boundary)
-    Fundo_boundary ();
-
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
 
@@ -271,8 +246,6 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
   entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend))));
   bset_undo_list (current_buffer,
                  Fcons (entry, BVAR (current_buffer, undo_list)));
-
-  current_buffer = obuf;
 }
 
 DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
@@ -300,8 +273,11 @@ but another undo command will undo to the previous boundary.  */)
        bset_undo_list (current_buffer,
                        Fcons (Qnil, BVAR (current_buffer, undo_list)));
     }
-  last_boundary_position = PT;
-  last_boundary_buffer = current_buffer;
+
+  Fset (Qundo_auto__last_boundary_cause, Qexplicit);
+  point_before_last_command_or_undo = PT;
+  buffer_before_last_command_or_undo = current_buffer;
+
   return Qnil;
 }
 
@@ -377,7 +353,6 @@ truncate_undo_list (struct buffer *b)
       && !NILP (Vundo_outer_limit_function))
     {
       Lisp_Object tem;
-      struct buffer *temp = last_undo_buffer;
 
       /* Normally the function this calls is undo-outer-limit-truncate.  */
       tem = call1 (Vundo_outer_limit_function, make_number (size_so_far));
@@ -388,10 +363,6 @@ truncate_undo_list (struct buffer *b)
          unbind_to (count, Qnil);
          return;
        }
-      /* That function probably used the minibuffer, and if so, that
-        changed last_undo_buffer.  Change it back so that we don't
-        force next change to make an undo boundary here.  */
-      last_undo_buffer = temp;
     }
 
   if (CONSP (next))
@@ -449,14 +420,15 @@ void
 syms_of_undo (void)
 {
   DEFSYM (Qinhibit_read_only, "inhibit-read-only");
+  DEFSYM (Qundo_auto__last_boundary_cause, "undo-auto--last-boundary-cause");
+  DEFSYM (Qexplicit, "explicit");
+
+  /* Marker for function call undo list elements.  */
   DEFSYM (Qapply, "apply");
 
   pending_boundary = Qnil;
   staticpro (&pending_boundary);
 
-  last_undo_buffer = NULL;
-  last_boundary_buffer = NULL;
-
   defsubr (&Sundo_boundary);
 
   DEFVAR_INT ("undo-limit", undo_limit,
@@ -511,5 +483,5 @@ so it must make sure not to do a lot of consing.  */);
 
   DEFVAR_BOOL ("undo-inhibit-record-point", undo_inhibit_record_point,
               doc: /* Non-nil means do not record `point' in `buffer-undo-list'.  */);
-  undo_inhibit_record_point = 0;
+  undo_inhibit_record_point = false;
 }