(displaying-byte-compile-warnings): Show
[bpt/emacs.git] / src / insdel.c
index d3c652b..a001c81 100644 (file)
@@ -27,6 +27,10 @@ Boston, MA 02111-1307, USA.  */
 #include "window.h"
 #include "blockinput.h"
 
+#ifndef NULL
+#define NULL 0
+#endif
+
 #define min(x, y) ((x) < (y) ? (x) : (y))
 
 static void insert_from_string_1 ();
@@ -274,8 +278,24 @@ adjust_markers (from, to, amount)
             but then this range contains no markers.  */
          if (mpos > from + amount && mpos <= from)
            {
-             record_marker_adjustment (marker, from + amount - mpos);
-             mpos = from + amount;
+             int before = mpos;
+             int after = from + amount;
+
+             mpos = after;
+
+             /* Compute the before and after positions
+                as buffer positions.  */
+             if (before > GPT + GAP_SIZE)
+               before -= GAP_SIZE;
+             else if (before > GPT)
+               before = GPT;
+
+             if (after > GPT + GAP_SIZE)
+               after -= GAP_SIZE;
+             else if (after > GPT)
+               after = GPT;
+
+             record_marker_adjustment (marker, after - before);
            }
        }
       if (mpos > from && mpos <= to)
@@ -425,7 +445,7 @@ insert_1 (string, length, inherit, prepare)
   register Lisp_Object temp;
 
   if (prepare)
-    prepare_to_modify_buffer (PT, PT);
+    prepare_to_modify_buffer (PT, PT, NULL);
 
   if (PT != GPT)
     move_gap (PT);
@@ -496,7 +516,7 @@ insert_from_string_1 (string, pos, length, inherit)
     error ("maximum buffer size exceeded");
 
   GCPRO1 (string);
-  prepare_to_modify_buffer (PT, PT);
+  prepare_to_modify_buffer (PT, PT, NULL);
 
   if (PT != GPT)
     move_gap (PT);
@@ -561,7 +581,7 @@ insert_from_buffer_1 (buf, pos, length, inherit)
   if (length + Z != XINT (temp))
     error ("maximum buffer size exceeded");
 
-  prepare_to_modify_buffer (PT, PT);
+  prepare_to_modify_buffer (PT, PT, NULL);
 
   if (PT != GPT)
     move_gap (PT);
@@ -675,6 +695,122 @@ insert_from_string_before_markers (string, pos, length, inherit)
     }
 }
 \f
+/* Replace the text from FROM to TO with NEW,
+   If PREPARE is nonzero, call prepare_to_modify_buffer.
+   If INHERIT, the newly inserted text should inherit text properties
+   from the surrounding non-deleted text.  */
+
+/* Note that this does not yet handle markers quite right.
+   Also it needs to record a single undo-entry that does a replacement
+   rather than a separate delete and insert.
+   That way, undo will also handle markers properly.  */
+
+void
+replace_range (from, to, new, prepare, inherit)
+     Lisp_Object new;
+     int from, to, prepare, inherit;
+{
+  int numdel;
+  int inslen = XSTRING (new)->size;
+  register Lisp_Object temp;
+  struct gcpro gcpro1;
+
+  GCPRO1 (new);
+
+  if (prepare)
+    {
+      int range_length = to - from;
+      prepare_to_modify_buffer (from, to, &from);
+      to = from + range_length;
+    }
+
+  /* Make args be valid */
+  if (from < BEGV)
+    from = BEGV;
+  if (to > ZV)
+    to = ZV;
+
+  UNGCPRO;
+
+  numdel = to - from;
+
+  /* Make sure point-max won't overflow after this insertion.  */
+  XSETINT (temp, Z - numdel + inslen);
+  if (Z - numdel + inslen != XINT (temp))
+    error ("maximum buffer size exceeded");
+
+  if (numdel <= 0 && inslen == 0)
+    return;
+
+  GCPRO1 (new);
+
+  /* Make sure the gap is somewhere in or next to what we are deleting.  */
+  if (from > GPT)
+    gap_right (from);
+  if (to < GPT)
+    gap_left (to, 0);
+
+  /* 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);
+
+  GAP_SIZE += numdel;
+  ZV -= numdel;
+  Z -= numdel;
+  GPT = from;
+  *(GPT_ADDR) = 0;             /* Put an anchor.  */
+
+  if (GPT - BEG < beg_unchanged)
+    beg_unchanged = GPT - BEG;
+  if (Z - GPT < end_unchanged)
+    end_unchanged = Z - GPT;
+
+  if (GAP_SIZE < inslen)
+    make_gap (inslen - GAP_SIZE);
+
+  record_insert (from, inslen);
+
+  bcopy (XSTRING (new)->data, GPT_ADDR, inslen);
+
+  /* Relocate point as if it were a marker.  */
+  if (from < PT)
+    adjust_point (from + inslen - (PT < to ? PT : to));
+
+#ifdef USE_TEXT_PROPERTIES
+  offset_intervals (current_buffer, PT, inslen - numdel);
+#endif
+
+  GAP_SIZE -= inslen;
+  GPT += inslen;
+  ZV += inslen;
+  Z += inslen;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
+
+  /* Adjust the overlay center as needed.  This must be done after
+     adjusting the markers that bound the overlays.  */
+  adjust_overlays_for_delete (from, numdel);
+  adjust_overlays_for_insert (from, inslen);
+  adjust_markers_for_insert (from, inslen);
+
+#ifdef USE_TEXT_PROPERTIES
+  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+  graft_intervals_into_buffer (XSTRING (new)->intervals, from, inslen,
+                              current_buffer, inherit);
+#endif
+
+  if (inslen == 0)
+    evaporate_overlays (from);
+
+  MODIFF++;
+  UNGCPRO;
+
+  signal_after_change (from, numdel, inslen);
+}
+\f
 /* Delete characters in current buffer
    from FROM up to (but not including) TO.  */
 
@@ -689,10 +825,17 @@ del_range (from, to)
 
 void
 del_range_1 (from, to, prepare)
-     register int from, to, prepare;
+     int from, to, prepare;
 {
   register int numdel;
 
+  if (prepare)
+    {
+      int range_length = to - from;
+      prepare_to_modify_buffer (from, to, &from);
+      to = from + range_length;
+    }
+
   /* Make args be valid */
   if (from < BEGV)
     from = BEGV;
@@ -708,9 +851,6 @@ del_range_1 (from, to, prepare)
   if (to < GPT)
     gap_left (to, 0);
 
-  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,
@@ -760,7 +900,7 @@ modify_region (buffer, start, end)
   if (buffer != old_buffer)
     set_buffer_internal (buffer);
 
-  prepare_to_modify_buffer (start, end);
+  prepare_to_modify_buffer (start, end, NULL);
 
   if (start - 1 < beg_unchanged
       || (unchanged_modified == MODIFF
@@ -780,22 +920,40 @@ modify_region (buffer, start, end)
   if (buffer != old_buffer)
     set_buffer_internal (old_buffer);
 }
-
+\f
 /* Check that it is okay to modify the buffer between START and END.
    Run the before-change-function, if any.  If intervals are in use,
    verify that the text to be modified is not read-only, and call
-   any modification properties the text may have. */
+   any modification properties the text may have.
+
+   If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
+   by holding its value temporarily in a marker.  */
 
 void
-prepare_to_modify_buffer (start, end)
+prepare_to_modify_buffer (start, end, preserve_ptr)
      int start, end;
+     int *preserve_ptr;
 {
   if (!NILP (current_buffer->read_only))
     Fbarf_if_buffer_read_only ();
 
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
   if (BUF_INTERVALS (current_buffer) != 0)
-    verify_interval_modification (current_buffer, start, end);
+    {
+      if (preserve_ptr)
+       {
+         Lisp_Object preserve_marker;
+         struct gcpro gcpro1;
+         preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil);
+         GCPRO1 (preserve_marker);
+         verify_interval_modification (current_buffer, start, end);
+         *preserve_ptr = marker_position (preserve_marker);
+         unchain_marker (preserve_marker);
+         UNGCPRO;
+       }
+      else
+       verify_interval_modification (current_buffer, start, end);
+    }
 
 #ifdef CLASH_DETECTION
   if (!NILP (current_buffer->file_truename)
@@ -813,7 +971,7 @@ prepare_to_modify_buffer (start, end)
           current_buffer->filename);
 #endif /* not CLASH_DETECTION */
 
-  signal_before_change (start, end);
+  signal_before_change (start, end, preserve_ptr);
 
   if (current_buffer->newline_cache)
     invalidate_region_cache (current_buffer,
@@ -827,29 +985,74 @@ prepare_to_modify_buffer (start, end)
   Vdeactivate_mark = Qt;
 }
 \f
+/* These macros work with an argument named `preserve_ptr'
+   and a local variable named `preserve_marker'.  */
+
+#define PRESERVE_VALUE                                                 \
+  if (preserve_ptr && NILP (preserve_marker))                          \
+    preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
+
+#define RESTORE_VALUE                                          \
+  if (! NILP (preserve_marker))                                        \
+    {                                                          \
+      *preserve_ptr = marker_position (preserve_marker);       \
+      unchain_marker (preserve_marker);                                \
+    }
+
+#define PRESERVE_START_END                     \
+  if (NILP (start_marker))                     \
+    start_marker = Fcopy_marker (start, Qnil); \
+  if (NILP (end_marker))                       \
+    end_marker = Fcopy_marker (end, Qnil);
+
+#define FETCH_START                            \
+  (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
+
+#define FETCH_END                              \
+  (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
+
 /* Signal a change to the buffer immediately before it happens.
-   START_INT and END_INT are the bounds of the text to be changed.  */
+   START_INT and END_INT are the bounds of the text to be changed.
+
+   If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
+   by holding its value temporarily in a marker.  */
 
 void
-signal_before_change (start_int, end_int)
+signal_before_change (start_int, end_int, preserve_ptr)
      int start_int, end_int;
+     int *preserve_ptr;
 {
   Lisp_Object start, end;
+  Lisp_Object start_marker, end_marker;
+  Lisp_Object preserve_marker;
+  struct gcpro gcpro1, gcpro2, gcpro3;
 
   start = make_number (start_int);
   end = make_number (end_int);
+  preserve_marker = Qnil;
+  start_marker = Qnil;
+  end_marker = Qnil;
+  GCPRO3 (preserve_marker, start_marker, end_marker);
 
   /* If buffer is unmodified, run a special hook for that case.  */
   if (SAVE_MODIFF >= MODIFF
       && !NILP (Vfirst_change_hook)
       && !NILP (Vrun_hooks))
-    call1 (Vrun_hooks, Qfirst_change_hook);
+    {
+      PRESERVE_VALUE;
+      PRESERVE_START_END;
+      call1 (Vrun_hooks, Qfirst_change_hook);
+    }
 
   /* 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))
-    call2 (Vbefore_change_function, start, end);
+    {
+      PRESERVE_VALUE;
+      PRESERVE_START_END;
+      call2 (Vbefore_change_function, FETCH_START, FETCH_END);
+    }
 
   /* Now run the before-change-functions if any.  */
   if (!NILP (Vbefore_change_functions))
@@ -859,6 +1062,9 @@ signal_before_change (start_int, end_int)
       Lisp_Object after_change_functions;
       struct gcpro gcpro1, gcpro2;
 
+      PRESERVE_VALUE;
+      PRESERVE_START_END;
+
       /* "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.  */
@@ -870,8 +1076,8 @@ signal_before_change (start_int, end_int)
 
       /* Actually run the hook functions.  */
       args[0] = Qbefore_change_functions;
-      args[1] = start;
-      args[2] = end;
+      args[1] = FETCH_START;
+      args[2] = FETCH_END;
       run_hook_list_with_args (before_change_functions, 3, args);
 
       /* "Unbind" the variables we "bound" to nil.  */
@@ -882,7 +1088,18 @@ signal_before_change (start_int, end_int)
 
   if (!NILP (current_buffer->overlays_before)
       || !NILP (current_buffer->overlays_after))
-    report_overlay_modification (start, end, 0, start, end, Qnil);
+    {
+      PRESERVE_VALUE;
+      report_overlay_modification (FETCH_START, FETCH_END, 0,
+                                  FETCH_START, FETCH_END, Qnil);
+    }
+
+  if (! NILP (start_marker))
+    free_marker (start_marker);
+  if (! NILP (end_marker))
+    free_marker (end_marker);
+  RESTORE_VALUE;
+  UNGCPRO;
 }
 
 /* Signal a change immediately after it happens.
@@ -1010,7 +1227,8 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
   for (tail = combine_after_change_list; CONSP (tail);
        tail = XCONS (tail)->cdr)
     {
-      Lisp_Object elt, thisbeg, thisend, thischange;
+      Lisp_Object elt;
+      int thisbeg, thisend, thischange;
 
       /* Extract the info from the next element.  */
       elt = XCONS (tail)->car;