]> code.delx.au - gnu-emacs/blobdiff - src/insdel.c
(modify-face): New function.
[gnu-emacs] / src / insdel.c
index a1b3b1ff113fdff7a756d040c971728ba82bee50..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,12 +556,23 @@ del_range (from, to)
   if (Z - GPT < end_unchanged)
     end_unchanged = Z - GPT;
 
+  evaporate_overlays (from);
   signal_after_change (from, numdel, 0);
 }
 \f
-modify_region (start, end)
+/* Call this if you're about to change the region of BUFFER from START
+   to END.  This checks the read-only properties of the region, calls
+   the necessary modification hooks, and warns the next redisplay that
+   it should pay attention to that area.  */
+modify_region (buffer, start, end)
+     struct buffer *buffer;
      int start, end;
 {
+  struct buffer *old_buffer = current_buffer;
+
+  if (buffer != old_buffer)
+    set_buffer_internal (buffer);
+
   prepare_to_modify_buffer (start, end);
 
   if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
@@ -483,7 +580,13 @@ modify_region (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)
+    set_buffer_internal (old_buffer);
 }
 
 /* Check that it is okay to modify the buffer between START and END.
@@ -498,7 +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);
+
+  if (!NILP (current_buffer->overlays_before)
+      || !NILP (current_buffer->overlays_after))
+    verify_overlay_modification (start, end);
 
 #ifdef CLASH_DETECTION
   if (!NILP (current_buffer->filename)
@@ -533,7 +641,21 @@ after_change_function_restore (value)
   Vafter_change_function = value;
 }
 
-/* Signal a change to the buffer immediatly before it happens.
+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.  */
 
@@ -553,19 +675,55 @@ 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 immediatly after it happens.
+/* Signal a change immediately after it happens.
    POS is the address of the start of the changed text.
    LENDEL is the number of characters of the text before the change.
    (Not the whole buffer; just the part that was changed.)
@@ -584,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);
+    }
 }