]> code.delx.au - gnu-emacs/blobdiff - src/insdel.c
(set-auto-mode): Run multiple mode: specs in left-to-right order.
[gnu-emacs] / src / insdel.c
index 1113e9bfb24fdc98e5ebc3effb0655254da58bdf..9f505361cc0fbf7489e7cd3011f58e5ecc16c5d1 100644 (file)
@@ -1,11 +1,11 @@
 /* Buffer insertion/deletion and gap motion for GNU Emacs.
-   Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1993, 1994, 1995 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 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
@@ -25,7 +26,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "window.h"
 #include "blockinput.h"
 
-static void insert_1 ();
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
 static void insert_from_string_1 ();
 static void insert_from_buffer_1 ();
 static void gap_left ();
@@ -36,6 +38,7 @@ static void adjust_point ();
 /* Move gap to position `pos'.
    Note that this can quit!  */
 
+void
 move_gap (pos)
      int pos;
 {
@@ -207,11 +210,16 @@ gap_right (pos)
   QUIT;
 }
 
-/* Add `amount' to the position of every marker in the current buffer
-   whose current position is between `from' (exclusive) and `to' (inclusive).
+/* Add AMOUNT to the position of every marker in the current buffer
+   whose current position is between FROM (exclusive) and TO (inclusive).
+
    Also, any markers past the outside of that interval, in the direction
    of adjustment, are first moved back to the near end of the interval
-   and then adjusted by `amount'.  */
+   and then adjusted by AMOUNT.
+
+   When the latter adjustment is done, if AMOUNT is negative,
+   we record the adjustment for undo.  (This case happens only for
+   deletion.)  */
 
 static void
 adjust_markers (from, to, amount)
@@ -221,7 +229,7 @@ adjust_markers (from, to, amount)
   register struct Lisp_Marker *m;
   register int mpos;
 
-  marker = current_buffer->markers;
+  marker = BUF_MARKERS (current_buffer);
 
   while (!NILP (marker))
     {
@@ -234,8 +242,14 @@ adjust_markers (from, to, amount)
        }
       else
        {
+         /* Here's the case where a marker is inside text being deleted.
+            AMOUNT can be negative for gap motion, too,
+            but then this range contains no markers.  */
          if (mpos > from + amount && mpos <= from)
-           mpos = from + amount;
+           {
+             record_marker_adjustment (marker, from + amount - mpos);
+             mpos = from + amount;
+           }
        }
       if (mpos > from && mpos <= to)
        mpos += amount;
@@ -244,21 +258,43 @@ adjust_markers (from, to, amount)
     }
 }
 
+/* Adjust markers whose insertion-type is t
+   for an insertion of AMOUNT characters at POS.  */
+
+static void
+adjust_markers_for_insert (pos, amount)
+     register int pos, amount;
+{
+  Lisp_Object marker;
+
+  marker = BUF_MARKERS (current_buffer);
+
+  while (!NILP (marker))
+    {
+      register struct Lisp_Marker *m = XMARKER (marker);
+      if (m->insertion_type && m->bufpos == pos)
+       m->bufpos += 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
+   either the old or the new value of point is out of sync with the
    current set of intervals.  */
 static void
 adjust_point (amount)
+     int amount;
 {
-  current_buffer->text.pt += amount;
+  BUF_PT (current_buffer) += amount;
 }
 \f
 /* Make the gap INCREMENT characters longer.  */
 
+void
 make_gap (increment)
      int increment;
 {
@@ -270,6 +306,14 @@ make_gap (increment)
   /* If we have to get more space, get enough to last a while.  */
   increment += 2000;
 
+  /* Don't allow a buffer size that won't fit in an int
+     even if it will fit in a Lisp integer.
+     That won't work because so many places use `int'.  */
+     
+  if (Z - BEG + GAP_SIZE + increment
+      >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
+    error ("Buffer exceeds maximum size");
+
   BLOCK_INPUT;
   result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
 
@@ -309,42 +353,40 @@ make_gap (increment)
    DO NOT use this for the contents of a Lisp string or a Lisp buffer!
    prepare_to_modify_buffer could relocate the text.  */
 
+void
 insert (string, length)
      register unsigned char *string;
      register length;
 {
   if (length > 0)
     {
-      insert_1 (string, length, 0);
+      insert_1 (string, length, 0, 1);
       signal_after_change (PT-length, 0, length);
     }
 }
 
+void
 insert_and_inherit (string, length)
      register unsigned char *string;
      register length;
 {
   if (length > 0)
     {
-      insert_1 (string, length, 1);
+      insert_1 (string, length, 1, 1);
       signal_after_change (PT-length, 0, length);
     }
 }
 
-static void
-insert_1 (string, length, inherit)
+void
+insert_1 (string, length, inherit, prepare)
      register unsigned char *string;
-     register length;
-     int inherit;
+     register int length;
+     int inherit, prepare;
 {
   register Lisp_Object temp;
 
-  /* Make sure point-max won't overflow after this insertion.  */
-  XSETINT (temp, length + Z);
-  if (length + Z != XINT (temp))
-    error ("maximum buffer size exceeded");
-
-  prepare_to_modify_buffer (PT, PT);
+  if (prepare)
+    prepare_to_modify_buffer (PT, PT);
 
   if (PT != GPT)
     move_gap (PT);
@@ -357,7 +399,7 @@ insert_1 (string, length, inherit)
   bcopy (string, GPT_ADDR, length);
 
 #ifdef USE_TEXT_PROPERTIES
-  if (current_buffer->intervals != 0)
+  if (BUF_INTERVALS (current_buffer) != 0)
     /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
     offset_intervals (current_buffer, PT, length);
 #endif
@@ -366,10 +408,12 @@ insert_1 (string, length, inherit)
   GPT += length;
   ZV += length;
   Z += length;
+  adjust_overlays_for_insert (PT, length);
+  adjust_markers_for_insert (PT, length);
   adjust_point (length);
 
 #ifdef USE_TEXT_PROPERTIES
-  if (!inherit && current_buffer->intervals != 0)
+  if (!inherit && BUF_INTERVALS (current_buffer) != 0)
     Fset_text_properties (make_number (PT - length), make_number (PT),
                          Qnil, Qnil);
 #endif
@@ -384,6 +428,7 @@ insert_1 (string, length, inherit)
    before we bcopy the stuff into the buffer, and relocate the string
    without insert noticing.  */
 
+void
 insert_from_string (string, pos, length, inherit)
      Lisp_Object string;
      register int pos, length;
@@ -431,6 +476,8 @@ insert_from_string_1 (string, pos, length, inherit)
   GPT += length;
   ZV += length;
   Z += length;
+  adjust_overlays_for_insert (PT, length);
+  adjust_markers_for_insert (PT, length);
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
   graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
@@ -497,7 +544,7 @@ insert_from_buffer_1 (buf, pos, length, inherit)
           GPT_ADDR + chunk, length - chunk);
 
 #ifdef USE_TEXT_PROPERTIES
-  if (current_buffer->intervals != 0)
+  if (BUF_INTERVALS (current_buffer) != 0)
     offset_intervals (current_buffer, PT, length);
 #endif
 
@@ -505,10 +552,13 @@ insert_from_buffer_1 (buf, pos, length, inherit)
   GPT += length;
   ZV += length;
   Z += length;
+  adjust_overlays_for_insert (PT, length);
+  adjust_markers_for_insert (PT, length);
   adjust_point (length);
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  graft_intervals_into_buffer (copy_intervals (buf->intervals, pos, length),
+  graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
+                                              pos, length),
                               PT - length, length, current_buffer, inherit);
 }
 
@@ -535,6 +585,7 @@ insert_string (s)
    Don't use this function to insert part of a Lisp string,
    since gc could happen and relocate it.  */
 
+void
 insert_before_markers (string, length)
      unsigned char *string;
      register int length;
@@ -542,12 +593,13 @@ insert_before_markers (string, length)
   if (length > 0)
     {
       register int opoint = PT;
-      insert_1 (string, length, 0);
+      insert_1 (string, length, 0, 1);
       adjust_markers (opoint - 1, opoint, length);
       signal_after_change (PT-length, 0, length);
     }
 }
 
+void
 insert_before_markers_and_inherit (string, length)
      unsigned char *string;
      register int length;
@@ -555,7 +607,7 @@ insert_before_markers_and_inherit (string, length)
   if (length > 0)
     {
       register int opoint = PT;
-      insert_1 (string, length, 1);
+      insert_1 (string, length, 1, 1);
       adjust_markers (opoint - 1, opoint, length);
       signal_after_change (PT-length, 0, length);
     }
@@ -563,6 +615,7 @@ insert_before_markers_and_inherit (string, length)
 
 /* Insert part of a Lisp string, relocating markers after.  */
 
+void
 insert_from_string_before_markers (string, pos, length, inherit)
      Lisp_Object string;
      register int pos, length;
@@ -580,14 +633,16 @@ insert_from_string_before_markers (string, pos, length, inherit)
 /* Delete characters in current buffer
    from FROM up to (but not including) TO.  */
 
+void
 del_range (from, to)
      register int from, to;
 {
-  return del_range_1 (from, to, 1);
+  del_range_1 (from, to, 1);
 }
 
 /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.  */
 
+void
 del_range_1 (from, to, prepare)
      register int from, to, prepare;
 {
@@ -611,6 +666,12 @@ del_range_1 (from, to, prepare)
   if (prepare)
     prepare_to_modify_buffer (from, to);
 
+  /* Relocate all markers pointing into the new, larger gap
+     to point at the end of the text before the gap.
+     This has to be done before recording the deletion,
+     so undo handles this after reinserting the text.  */
+  adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
+
   record_delete (from, numdel);
   MODIFF++;
 
@@ -621,9 +682,9 @@ del_range_1 (from, to, prepare)
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
   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.  */
-  adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
+  /* Adjust the overlay center as needed.  This must be done after
+     adjusting the markers that bound the overlays.  */
+  adjust_overlays_for_delete (from, numdel);
 
   GAP_SIZE += numdel;
   ZV -= numdel;
@@ -643,6 +704,7 @@ del_range_1 (from, to, prepare)
    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.  */
+void
 modify_region (buffer, start, end)
      struct buffer *buffer;
      int start, end;
@@ -660,10 +722,12 @@ modify_region (buffer, start, end)
       || unchanged_modified == MODIFF)
     end_unchanged = Z - end;
 
-  if (MODIFF <= current_buffer->save_modified)
+  if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
   MODIFF++;
 
+  buffer->point_before_scroll = Qnil;
+
   if (buffer != old_buffer)
     set_buffer_internal (old_buffer);
 }
@@ -673,6 +737,7 @@ modify_region (buffer, start, end)
    verify that the text to be modified is not read-only, and call
    any modification properties the text may have. */
 
+void
 prepare_to_modify_buffer (start, end)
      Lisp_Object start, end;
 {
@@ -680,17 +745,19 @@ prepare_to_modify_buffer (start, end)
     Fbarf_if_buffer_read_only ();
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  if (current_buffer->intervals != 0)
+  if (BUF_INTERVALS (current_buffer) != 0)
     verify_interval_modification (current_buffer, start, end);
 
 #ifdef CLASH_DETECTION
-  if (!NILP (current_buffer->filename)
-      && current_buffer->save_modified >= MODIFF)
-    lock_file (current_buffer->filename);
+  if (!NILP (current_buffer->file_truename)
+      /* Make binding buffer-file-name to nil effective.  */
+      && !NILP (current_buffer->filename)
+      && SAVE_MODIFF >= MODIFF)
+    lock_file (current_buffer->file_truename);
 #else
   /* At least warn if this file has changed on disk since it was visited.  */
   if (!NILP (current_buffer->filename)
-      && current_buffer->save_modified >= MODIFF
+      && SAVE_MODIFF >= MODIFF
       && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
       && !NILP (Ffile_exists_p (current_buffer->filename)))
     call1 (intern ("ask-user-about-supersession-threat"),
@@ -711,99 +778,53 @@ prepare_to_modify_buffer (start, end)
   Vdeactivate_mark = Qt;
 }
 \f
-static Lisp_Object
-before_change_function_restore (value)
-     Lisp_Object value;
-{
-  Vbefore_change_function = value;
-}
-
-static Lisp_Object
-after_change_function_restore (value)
-     Lisp_Object 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.  */
 
+void
 signal_before_change (start, end)
      Lisp_Object start, end;
 {
   /* If buffer is unmodified, run a special hook for that case.  */
-  if (current_buffer->save_modified >= MODIFF
+  if (SAVE_MODIFF >= MODIFF
       && !NILP (Vfirst_change_hook)
       && !NILP (Vrun_hooks))
     call1 (Vrun_hooks, Qfirst_change_hook);
 
-  /* Now in any case run the before-change-function if any.  */
+  /* Run the before-change-function if any.
+     We don't bother "binding" this variable to nil
+     because it is obsolete anyway and new code should not use it.  */
   if (!NILP (Vbefore_change_function))
-    {
-      int count = specpdl_ptr - specpdl;
-      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);
-    }
+    call2 (Vbefore_change_function, start, end);
 
-  /* Now in any case run the before-change-function if any.  */
+  /* Now run the before-change-functions 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;
+      Lisp_Object args[3];
+      Lisp_Object before_change_functions;
+      Lisp_Object after_change_functions;
+      struct gcpro gcpro1, gcpro2;
+
+      /* "Bind" before-change-functions and after-change-functions
+        to nil--but in a way that errors don't know about.
+        That way, if there's an error in them, they will stay nil.  */
+      before_change_functions = Vbefore_change_functions;
+      after_change_functions = Vafter_change_functions;
       Vbefore_change_functions = Qnil;
-
-      while (CONSP (functions))
-       {
-         call2 (XCONS (functions)->car, start, end);
-         functions = XCONS (functions)->cdr;
-       }
-      unbind_to (count, Qnil);
+      Vafter_change_functions = Qnil;
+      GCPRO2 (before_change_functions, after_change_functions);
+
+      /* Actually run the hook functions.  */
+      args[0] = Qbefore_change_functions;
+      args[1] = start;
+      args[2] = end;
+      run_hook_list_with_args (before_change_functions, 3, args);
+
+      /* "Unbind" the variables we "bound" to nil.  */
+      Vbefore_change_functions = before_change_functions;
+      Vafter_change_functions = after_change_functions;
+      UNGCPRO;
     }
 
   if (!NILP (current_buffer->overlays_before)
@@ -815,70 +836,61 @@ signal_before_change (start, end)
    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.)
-   LENINS is the number of characters in the changed text.
-
-   (Hence POS + LENINS - LENDEL is the position after the changed text.)  */
+   LENINS is the number of characters in that part of the text
+   after the change.  */
 
+void
 signal_after_change (pos, lendel, lenins)
      int pos, lendel, lenins;
 {
+  /* Run the after-change-function if any.
+     We don't bother "binding" this variable to nil
+     because it is obsolete anyway and new code should not use it.  */
   if (!NILP (Vafter_change_function))
-    {
-      int count = specpdl_ptr - specpdl;
-      Lisp_Object function;
-      function = Vafter_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;
+    call3 (Vafter_change_function,
+          make_number (pos), make_number (pos + lenins),
+          make_number (lendel));
 
-      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;
+      Lisp_Object args[4];
+      Lisp_Object before_change_functions;
+      Lisp_Object after_change_functions;
+      struct gcpro gcpro1, gcpro2;
+
+      /* "Bind" before-change-functions and after-change-functions
+        to nil--but in a way that errors don't know about.
+        That way, if there's an error in them, they will stay nil.  */
+      before_change_functions = Vbefore_change_functions;
+      after_change_functions = Vafter_change_functions;
       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);
+      Vafter_change_functions = Qnil;
+      GCPRO2 (before_change_functions, after_change_functions);
+
+      /* Actually run the hook functions.  */
+      args[0] = Qafter_change_functions;
+      XSETFASTINT (args[1], pos);
+      XSETFASTINT (args[2], pos + lenins);
+      XSETFASTINT (args[3], lendel);
+      run_hook_list_with_args (after_change_functions,
+                              4, args);
+
+      /* "Unbind" the variables we "bound" to nil.  */
+      Vbefore_change_functions = before_change_functions;
+      Vafter_change_functions = after_change_functions;
+      UNGCPRO;
     }
 
   if (!NILP (current_buffer->overlays_before)
       || !NILP (current_buffer->overlays_after))
     report_overlay_modification (make_number (pos),
-                                make_number (pos + lenins - lendel),
+                                make_number (pos + lenins),
                                 1,
                                 make_number (pos), make_number (pos + lenins),
                                 make_number (lendel));
+
+  /* After an insertion, call the text properties
+     insert-behind-hooks or insert-in-front-hooks.  */
+  if (lendel == 0)
+    report_interval_modification (pos, pos + lenins);
 }