]> code.delx.au - gnu-emacs/blobdiff - src/insdel.c
(modify-face): New function.
[gnu-emacs] / src / insdel.c
index f9263fabfd959c150a56a6e4b54ffbf8f287ea7a..74f8503422bd120939f871775ddef43c71ea3127 100644 (file)
@@ -1,5 +1,5 @@
 /* Buffer insertion/deletion and gap motion for GNU Emacs.
-   Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,13 +18,20 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
-#include "config.h"
+#include <config.h>
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
 #include "window.h"
 #include "blockinput.h"
 
+static void insert_1 ();
+static void insert_from_string_1 ();
+static void gap_left ();
+static void gap_right ();
+static void adjust_markers ();
+static void adjust_point ();
+
 /* Move gap to position `pos'.
    Note that this can quit!  */
 
@@ -40,6 +47,7 @@ move_gap (pos)
 /* Move the gap to POS, which is less than the current GPT.
    If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged.  */
 
+static void
 gap_left (pos, newgap)
      register int pos;
      int newgap;
@@ -122,6 +130,7 @@ gap_left (pos, newgap)
   QUIT;
 }
 
+static void
 gap_right (pos)
      register int pos;
 {
@@ -203,6 +212,7 @@ gap_right (pos)
    of adjustment, are first moved back to the near end of the interval
    and then adjusted by `amount'.  */
 
+static void
 adjust_markers (from, to, amount)
      register int from, to, amount;
 {
@@ -232,6 +242,19 @@ adjust_markers (from, to, amount)
       marker = m->chain;
     }
 }
+
+/* Add the specified amount to point.  This is used only when the value
+   of point changes due to an insert or delete; it does not represent
+   a conceptual change in point as a marker.  In particular, point is
+   not crossing any interval boundaries, so there's no need to use the
+   usual SET_PT macro.  In fact it would be incorrect to do so, because
+   either the old or the new value of point is out of synch with the
+   current set of intervals.  */
+static void
+adjust_point (amount)
+{
+  current_buffer->text.pt += amount;
+}
 \f
 /* Make the gap INCREMENT characters longer.  */
 
@@ -284,38 +307,66 @@ insert (string, length)
      register unsigned char *string;
      register length;
 {
-  register Lisp_Object temp;
+  if (length > 0)
+    {
+      insert_1 (string, length, 0);
+      signal_after_change (PT-length, 0, length);
+    }
+}
 
-  if (length < 1)
-    return;
+insert_and_inherit (string, length)
+     register unsigned char *string;
+     register length;
+{
+  if (length > 0)
+    {
+      insert_1 (string, length, 1);
+      signal_after_change (PT-length, 0, length);
+    }
+}
+
+static void
+insert_1 (string, length, inherit)
+     register unsigned char *string;
+     register length;
+     int inherit;
+{
+  register Lisp_Object temp;
 
   /* Make sure point-max won't overflow after this insertion.  */
   XSET (temp, Lisp_Int, length + Z);
   if (length + Z != XINT (temp))
     error ("maximum buffer size exceeded");
 
-  prepare_to_modify_buffer (point, point);
+  prepare_to_modify_buffer (PT, PT);
 
-  if (point != GPT)
-    move_gap (point);
+  if (PT != GPT)
+    move_gap (PT);
   if (GAP_SIZE < length)
     make_gap (length - GAP_SIZE);
 
-  record_insert (point, length);
+  record_insert (PT, length);
   MODIFF++;
 
   bcopy (string, GPT_ADDR, length);
 
-  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  offset_intervals (current_buffer, point, length);
+#ifdef USE_TEXT_PROPERTIES
+  if (current_buffer->intervals != 0)
+    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
+    offset_intervals (current_buffer, PT, length);
+#endif
 
   GAP_SIZE -= length;
   GPT += length;
   ZV += length;
   Z += length;
-  SET_PT (point + length);
+  adjust_point (length);
 
-  signal_after_change (point-length, 0, length);
+#ifdef USE_TEXT_PROPERTIES
+  if (!inherit && current_buffer->intervals != 0)
+    Fset_text_properties (make_number (PT - length), make_number (PT),
+                         Qnil, Qnil);
+#endif
 }
 
 /* Insert the part of the text of STRING, a Lisp object assumed to be
@@ -327,37 +378,48 @@ insert (string, length)
    before we bcopy the stuff into the buffer, and relocate the string
    without insert noticing.  */
 
-insert_from_string (string, pos, length)
+insert_from_string (string, pos, length, inherit)
      Lisp_Object string;
      register int pos, length;
+     int inherit;
+{
+  if (length > 0)
+    {
+      insert_from_string_1 (string, pos, length, inherit);
+      signal_after_change (PT-length, 0, length);
+    }
+}
+
+static void
+insert_from_string_1 (string, pos, length, inherit)
+     Lisp_Object string;
+     register int pos, length;
+     int inherit;
 {
   register Lisp_Object temp;
   struct gcpro gcpro1;
 
-  if (length < 1)
-    return;
-
   /* Make sure point-max won't overflow after this insertion.  */
   XSET (temp, Lisp_Int, length + Z);
   if (length + Z != XINT (temp))
     error ("maximum buffer size exceeded");
 
   GCPRO1 (string);
-  prepare_to_modify_buffer (point, point);
+  prepare_to_modify_buffer (PT, PT);
 
-  if (point != GPT)
-    move_gap (point);
+  if (PT != GPT)
+    move_gap (PT);
   if (GAP_SIZE < length)
     make_gap (length - GAP_SIZE);
 
-  record_insert (point, length);
+  record_insert (PT, length);
   MODIFF++;
   UNGCPRO;
 
   bcopy (XSTRING (string)->data, GPT_ADDR, length);
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  offset_intervals (current_buffer, point, length);
+  offset_intervals (current_buffer, PT, length);
 
   GAP_SIZE -= length;
   GPT += length;
@@ -365,12 +427,10 @@ insert_from_string (string, pos, length)
   Z += length;
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  graft_intervals_into_buffer (XSTRING (string)->intervals, point,
-                              current_buffer);
-
-  SET_PT (point + length);
+  graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
+                              current_buffer, inherit);
 
-  signal_after_change (point-length, 0, length);
+  adjust_point (length);
 }
 
 /* Insert the character C before point */
@@ -400,20 +460,42 @@ insert_before_markers (string, length)
      unsigned char *string;
      register int length;
 {
-  register int opoint = point;
-  insert (string, length);
-  adjust_markers (opoint - 1, opoint, length);
+  if (length > 0)
+    {
+      register int opoint = PT;
+      insert_1 (string, length, 1);
+      adjust_markers (opoint - 1, opoint, length);
+      signal_after_change (PT-length, 0, length);
+    }
+}
+
+insert_before_markers_and_inherit (string, length)
+     unsigned char *string;
+     register int length;
+{
+  if (length > 0)
+    {
+      register int opoint = PT;
+      insert_1 (string, length, 1);
+      adjust_markers (opoint - 1, opoint, length);
+      signal_after_change (PT-length, 0, length);
+    }
 }
 
 /* Insert part of a Lisp string, relocating markers after.  */
 
-insert_from_string_before_markers (string, pos, length)
+insert_from_string_before_markers (string, pos, length, inherit)
      Lisp_Object string;
      register int pos, length;
+     int inherit;
 {
-  register int opoint = point;
-  insert_from_string (string, pos, length);
-  adjust_markers (opoint - 1, opoint, length);
+  if (length > 0)
+    {
+      register int opoint = PT;
+      insert_from_string_1 (string, pos, length, inherit);
+      adjust_markers (opoint - 1, opoint, length);
+      signal_after_change (PT-length, 0, length);
+    }
 }
 \f
 /* Delete characters in current buffer
@@ -421,6 +503,14 @@ insert_from_string_before_markers (string, pos, length)
 
 del_range (from, to)
      register int from, to;
+{
+  return del_range_1 (from, to, 1);
+}
+
+/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.  */
+
+del_range_1 (from, to, prepare)
+     register int from, to, prepare;
 {
   register int numdel;
 
@@ -439,22 +529,18 @@ del_range (from, to)
   if (to < GPT)
     gap_left (to, 0);
 
-  prepare_to_modify_buffer (from, to);
+  if (prepare)
+    prepare_to_modify_buffer (from, to);
 
   record_delete (from, numdel);
   MODIFF++;
 
   /* Relocate point as if it were a marker.  */
-  if (from < point)
-    {
-      if (point < to)
-       SET_PT (from);
-      else
-       SET_PT (point - numdel);
-    }
+  if (from < PT)
+    adjust_point (from - (PT < to ? PT : to));
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  offset_intervals (current_buffer, point, - numdel);
+  offset_intervals (current_buffer, from, - numdel);
 
   /* Relocate all markers pointing into the new, larger gap
      to point at the end of the text before the gap.  */
@@ -470,6 +556,7 @@ del_range (from, to)
   if (Z - GPT < end_unchanged)
     end_unchanged = Z - GPT;
 
+  evaporate_overlays (from);
   signal_after_change (from, numdel, 0);
 }
 \f
@@ -493,6 +580,9 @@ modify_region (buffer, start, end)
   if (Z - end < end_unchanged
       || unchanged_modified == MODIFF)
     end_unchanged = Z - end;
+
+  if (MODIFF <= current_buffer->save_modified)
+    record_first_change ();
   MODIFF++;
 
   if (buffer != old_buffer)
@@ -511,9 +601,12 @@ prepare_to_modify_buffer (start, end)
     Fbarf_if_buffer_read_only ();
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  verify_interval_modification (current_buffer, start, end);
+  if (current_buffer->intervals != 0)
+    verify_interval_modification (current_buffer, start, end);
 
-  verify_overlay_modification (start, end);
+  if (!NILP (current_buffer->overlays_before)
+      || !NILP (current_buffer->overlays_after))
+    verify_overlay_modification (start, end);
 
 #ifdef CLASH_DETECTION
   if (!NILP (current_buffer->filename)
@@ -548,6 +641,20 @@ after_change_function_restore (value)
   Vafter_change_function = value;
 }
 
+static Lisp_Object
+before_change_functions_restore (value)
+     Lisp_Object value;
+{
+  Vbefore_change_functions = value;
+}
+
+static Lisp_Object
+after_change_functions_restore (value)
+     Lisp_Object value;
+{
+  Vafter_change_functions = value;
+}
+
 /* Signal a change to the buffer immediately before it happens.
    START and END are the bounds of the text to be changed,
    as Lisp objects.  */
@@ -568,16 +675,52 @@ signal_before_change (start, end)
       Lisp_Object function;
 
       function = Vbefore_change_function;
+
       record_unwind_protect (after_change_function_restore,
                             Vafter_change_function);
       record_unwind_protect (before_change_function_restore,
                             Vbefore_change_function);
+      record_unwind_protect (after_change_functions_restore,
+                            Vafter_change_functions);
+      record_unwind_protect (before_change_functions_restore,
+                            Vbefore_change_functions);
       Vafter_change_function = Qnil;
       Vbefore_change_function = Qnil;
+      Vafter_change_functions = Qnil;
+      Vbefore_change_functions = Qnil;
 
       call2 (function, start, end);
       unbind_to (count, Qnil);
     }
+
+  /* Now in any case run the before-change-function if any.  */
+  if (!NILP (Vbefore_change_functions))
+    {
+      int count = specpdl_ptr - specpdl;
+      Lisp_Object functions;
+
+      functions = Vbefore_change_functions;
+
+      record_unwind_protect (after_change_function_restore,
+                            Vafter_change_function);
+      record_unwind_protect (before_change_function_restore,
+                            Vbefore_change_function);
+      record_unwind_protect (after_change_functions_restore,
+                            Vafter_change_functions);
+      record_unwind_protect (before_change_functions_restore,
+                            Vbefore_change_functions);
+      Vafter_change_function = Qnil;
+      Vbefore_change_function = Qnil;
+      Vafter_change_functions = Qnil;
+      Vbefore_change_functions = Qnil;
+
+      while (CONSP (functions))
+       {
+         call2 (XCONS (functions)->car, start, end);
+         functions = XCONS (functions)->cdr;
+       }
+      unbind_to (count, Qnil);
+    }
 }
 
 /* Signal a change immediately after it happens.
@@ -599,11 +742,45 @@ signal_after_change (pos, lendel, lenins)
                             Vafter_change_function);
       record_unwind_protect (before_change_function_restore,
                             Vbefore_change_function);
+      record_unwind_protect (after_change_functions_restore,
+                            Vafter_change_functions);
+      record_unwind_protect (before_change_functions_restore,
+                            Vbefore_change_functions);
       Vafter_change_function = Qnil;
       Vbefore_change_function = Qnil;
+      Vafter_change_functions = Qnil;
+      Vbefore_change_functions = Qnil;
 
       call3 (function, make_number (pos), make_number (pos + lenins),
             make_number (lendel));
       unbind_to (count, Qnil);
     }
+  if (!NILP (Vafter_change_functions))
+    {
+      int count = specpdl_ptr - specpdl;
+      Lisp_Object functions;
+      functions = Vafter_change_functions;
+
+      record_unwind_protect (after_change_function_restore,
+                            Vafter_change_function);
+      record_unwind_protect (before_change_function_restore,
+                            Vbefore_change_function);
+      record_unwind_protect (after_change_functions_restore,
+                            Vafter_change_functions);
+      record_unwind_protect (before_change_functions_restore,
+                            Vbefore_change_functions);
+      Vafter_change_function = Qnil;
+      Vbefore_change_function = Qnil;
+      Vafter_change_functions = Qnil;
+      Vbefore_change_functions = Qnil;
+
+      while (CONSP (functions))
+       {
+         call3 (XCONS (functions)->car,
+                make_number (pos), make_number (pos + lenins),
+                make_number (lendel));
+         functions = XCONS (functions)->cdr;
+       }
+      unbind_to (count, Qnil);
+    }
 }