changeset 16547:96ae48c20664

(signal_after_change): If Vcombine_after_change_calls, save up changes in combine_after_change_list. (Fcombine_after_change_execute) (Fcombine_after_change_execute_1): New subroutines. (syms_of_insdel): New function.
author Richard M. Stallman <rms@gnu.org>
date Sat, 09 Nov 1996 21:36:00 +0000
parents 06f92ef2857c
children 12915fed5a02
files src/insdel.c
diffstat 1 files changed, 138 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/insdel.c	Sat Nov 09 09:21:20 1996 +0000
+++ b/src/insdel.c	Sat Nov 09 21:36:00 1996 +0000
@@ -35,6 +35,27 @@
 static void adjust_markers ();
 static void adjust_point ();
 
+Lisp_Object Fcombine_after_change_execute ();
+
+/* Non-nil means don't call the after-change-functions right away,
+   just record an element in Vcombine_after_change_calls_list.  */
+Lisp_Object Vcombine_after_change_calls;
+
+/* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT)
+   describing changes which happened while combine_after_change_calls
+   was nonzero.  We use this to decide how to call them
+   once the deferral ends.
+
+   In each element.
+   BEG-UNCHANGED is the number of chars before the changed range.
+   END-UNCHANGED is the number of chars after the changed range,
+   and CHANGE-AMOUNT is the number of characters inserted by the change
+   (negative for a deletion).  */
+Lisp_Object combine_after_change_list;
+
+/* Buffer which combine_after_change_list is about.  */
+Lisp_Object combine_after_change_buffer;
+
 /* Move gap to position `pos'.
    Note that this can quit!  */
 
@@ -853,6 +874,33 @@
 signal_after_change (pos, lendel, lenins)
      int pos, lendel, lenins;
 {
+  /* If we are deferring calls to the after-change functions
+     and there are no before-change functions,
+     just record the args that we were going to use.  */
+  if (! NILP (Vcombine_after_change_calls)
+      && NILP (Vbefore_change_function) && NILP (Vbefore_change_functions)
+      && NILP (current_buffer->overlays_before)
+      && NILP (current_buffer->overlays_after))
+    {
+      Lisp_Object elt;
+
+      if (!NILP (combine_after_change_list)
+	  && current_buffer != XBUFFER (combine_after_change_buffer))
+	Fcombine_after_change_execute ();
+
+      elt = Fcons (make_number (pos - BEG),
+		   Fcons (make_number (Z - (pos - lendel + lenins)),
+			  Fcons (make_number (lenins - lendel), Qnil)));
+      combine_after_change_list
+	= Fcons (elt, combine_after_change_list);
+      combine_after_change_buffer = Fcurrent_buffer ();
+
+      return;
+    }
+
+  if (!NILP (combine_after_change_list)) 
+    Fcombine_after_change_execute ();
+
   /* 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.  */
@@ -904,3 +952,93 @@
   if (lendel == 0)
     report_interval_modification (pos, pos + lenins);
 }
+
+Lisp_Object
+Fcombine_after_change_execute_1 (val)
+     Lisp_Object val;
+{
+  Vcombine_after_change_calls = val;
+  return val;
+}
+
+DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
+  Scombine_after_change_execute, 0, 0, 0,
+  "This function is for use internally in `combine-after-change-calls'.")
+  ()
+{
+  register Lisp_Object val;
+  int count = specpdl_ptr - specpdl;
+  int beg, end, change;
+  int begpos, endpos;
+  Lisp_Object tail;
+
+  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
+  Fset_buffer (combine_after_change_buffer);
+
+  /* # chars unchanged at beginning of buffer.  */
+  beg = Z - BEG;
+  /* # chars unchanged at end of buffer.  */
+  end = beg;
+  /* Total amount of insertion (negative for deletion).  */
+  change = 0;
+
+  /* Scan the various individual changes,
+     accumulating the range info in BEG, END and CHANGE.  */
+  for (tail = combine_after_change_list; CONSP (tail);
+       tail = XCONS (tail)->cdr)
+    {
+      Lisp_Object elt, thisbeg, thisend, thischange;
+
+      /* Extract the info from the next element.  */
+      elt = XCONS (tail)->car;
+      if (! CONSP (elt))
+	continue;
+      thisbeg = XINT (XCONS (elt)->car);
+
+      elt = XCONS (elt)->cdr;
+      if (! CONSP (elt))
+	continue;
+      thisend = XINT (XCONS (elt)->car);
+
+      elt = XCONS (elt)->cdr;
+      if (! CONSP (elt))
+	continue;
+      thischange = XINT (XCONS (elt)->car);
+
+      /* Merge this range into the accumulated range.  */
+      change += thischange;
+      if (thisbeg < beg)
+	beg = thisbeg;
+      if (thisend < end)
+	end = thisend;
+    }
+
+  /* Get the current start and end positions of the range
+     that was changed.  */
+  begpos = BEG + beg;
+  endpos = Z - end;
+  
+  /* We are about to handle these, so discard them.  */
+  combine_after_change_list = Qnil;
+
+  /* Now run the after-change functions for real.
+     Turn off the flag that defers them.  */
+  record_unwind_protect (Fcombine_after_change_execute_1,
+			 Vcombine_after_change_calls);
+  signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
+
+  return unbind_to (count, val);
+}
+
+syms_of_insdel ()
+{
+  staticpro (&combine_after_change_list);
+  combine_after_change_list = Qnil;
+
+  DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls,
+     "Used internally by the `combine-after-change-calls' macro.");
+  Vcombine_after_change_calls = Qnil;
+
+  defsubr (&Scombine_after_change_execute);
+}