changeset 2052:48c83a34c005

(verify_interval_modification): Handle insertions specially. For non-insertions, check only the chars being changed. `modification-hooks' property is now a list of functions. (set_point): Ignore chars outside current restriction.
author Richard M. Stallman <rms@gnu.org>
date Sun, 07 Mar 1993 09:34:39 +0000
parents c1767ea45687
children 8bdcc55ebd8f
files src/intervals.c
diffstat 1 files changed, 114 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/intervals.c	Sun Mar 07 09:33:43 1993 +0000
+++ b/src/intervals.c	Sun Mar 07 09:34:39 1993 +0000
@@ -1,5 +1,5 @@
 /* Code for doing intervals.
-   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -1071,7 +1071,7 @@
   split_interval_right (slot, length + 1);
   return slot;
 }
-
+
 /* Insert the intervals of SOURCE into BUFFER at POSITION.
 
    This is used in insdel.c when inserting Lisp_Strings into
@@ -1225,7 +1225,7 @@
     }
   return Qnil;
 }
-
+
 /* Set point in BUFFER to POSITION.  If the target position is in
    after an invisible character which is not displayed with a special glyph,
    move back to an ok place to display.  */
@@ -1256,22 +1256,24 @@
     abort ();
 
   /* Position Z is really one past the last char in the buffer.  */
-  if (position == BUF_Z (buffer))
+  if (position == BUF_ZV (buffer))
     iposition = position - 1;
 
   /* Set TO to the interval containing the char after POSITION,
      and TOPREV to the interval containing the char before POSITION.
      Either one may be null.  They may be equal.  */
   to = find_interval (buffer->intervals, iposition);
-  if (to->position == position)
+  if (position == BUF_BEGV (buffer))
+    toprev = 0;
+  else if (to->position == position)
     toprev = previous_interval (to);
   else if (iposition != position)
     toprev = to, to = 0;
   else
     toprev = to;
 
-  buffer_point = (BUF_PT (buffer) == BUF_Z (buffer)
-		  ? BUF_Z (buffer) - 1
+  buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
+		  ? BUF_ZV (buffer) - 1
 		  : BUF_PT (buffer));
 
   /* Set FROM to the interval containing the char after PT,
@@ -1279,7 +1281,9 @@
      Either one may be null.  They may be equal.  */
   /* We could cache this and save time. */
   from = find_interval (buffer->intervals, buffer_point);
-  if (from->position == BUF_PT (buffer))
+  if (from->position == BUF_BEGV (buffer))
+    fromprev = 0;
+  else if (from->position == BUF_PT (buffer))
     fromprev = previous_interval (from);
   else if (buffer_point != BUF_PT (buffer))
     fromprev = from, from = 0;
@@ -1353,6 +1357,22 @@
 {
   buffer->text.pt = position;
 }
+
+/* Call the modification hook functions in LIST, each with START and END.  */
+
+static void
+call_mod_hooks (list, start, end)
+     Lisp_Object list, start, end;
+{
+  struct gcpro gcpro1;
+  GCPRO1 (list);
+  while (!NILP (list))
+    {
+      call2 (Fcar (list), start, end);
+      list = Fcdr (list);
+    }
+  UNGCPRO;
+}
 
 /* Check for read-only intervals and signal an error if we find one.
    Then check for any modification hooks in the range START up to
@@ -1367,12 +1387,16 @@
      int start, end;
 {
   register INTERVAL intervals = buf->intervals;
-  register INTERVAL i;
-  Lisp_Object hooks = Qnil;
-  register prev_mod_hook = Qnil;
-  register Lisp_Object mod_hook;
+  register INTERVAL i, prev;
+  Lisp_Object hooks;
+  register Lisp_Object prev_mod_hooks;
+  Lisp_Object mod_hooks;
   struct gcpro gcpro1;
 
+  hooks = Qnil;
+  prev_mod_hooks = Qnil;
+  mod_hooks = Qnil;
+
   if (NULL_INTERVAL_P (intervals))
     return;
 
@@ -1383,43 +1407,93 @@
       end = temp;
     }
 
-  if (start == BUF_Z (buf))
+  /* For an insert operation, check the two chars around the position.  */
+  if (start == end)
     {
-      /* This should not be getting called on empty buffers. */
-      if (BUF_Z (buf) == 1)
-	abort ();
+      INTERVAL prev;
+      Lisp_Object before, after;
+
+      /* Set I to the interval containing the char after START,
+	 and PREV to the interval containing the char before START.
+	 Either one may be null.  They may be equal.  */
+      i = find_interval (intervals,
+			 (start == BUF_ZV (buf) ? start - 1 : start));
+
+      if (start == BUF_BEGV (buf))
+	prev = 0;
+      if (i->position == start)
+	prev = previous_interval (i);
+      else if (i->position < start)
+	prev = i;
+      if (start == BUF_ZV (buf))
+	i = 0;
 
-      i = find_interval (intervals, start - 1);
-      if (! END_STICKY_P (i))
-	return;
+      if (NULL_INTERVAL_P (prev))
+	{
+	  after = textget (i, Qread_only);
+	  if (! NILP (after))
+	    error ("Attempt to insert within read-only text");
+	}
+      else if (NULL_INTERVAL_P (i))
+	{
+	  before = textget (prev, Qread_only);
+	  if (! NILP (before))
+	    error ("Attempt to insert within read-only text");
+	}
+      else
+	{
+	  before = textget (prev, Qread_only);
+	  after = textget (i, Qread_only);
+	  if (! NILP (before) && EQ (before, after))
+	    error ("Attempt to insert within read-only text");
+	}
+
+      /* Run both mod hooks (just once if they're the same).  */
+      if (!NULL_INTERVAL_P (prev))
+	prev_mod_hooks = textget (prev->plist, Qmodification_hooks);
+      if (!NULL_INTERVAL_P (i))
+	mod_hooks = textget (i->plist, Qmodification_hooks);
+      GCPRO1 (mod_hooks);
+      if (! NILP (prev_mod_hooks))
+	call_mod_hooks (prev_mod_hooks, make_number (start),
+			make_number (end));
+      UNGCPRO;
+      if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
+	call_mod_hooks (mod_hooks, make_number (start), make_number (end));
     }
   else
-    i = find_interval (intervals, start);
+    {
+      /* Loop over intervals on or next to START...END,
+	 collecting their hooks.  */
 
-  do
-    {
-      if (! INTERVAL_WRITABLE_P (i))
-	error ("Attempt to modify read-only text");
+      i = find_interval (intervals, start);
+      do
+	{
+	  if (! INTERVAL_WRITABLE_P (i))
+	    error ("Attempt to modify read-only text");
 
-      mod_hook = Fget (Qmodification, i->plist);
-      if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook))
-	{
-	  hooks = Fcons (mod_hook, hooks);
-	  prev_mod_hook = mod_hook;
+	  mod_hooks = textget (i->plist, Qmodification_hooks);
+	  if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
+	    {
+	      hooks = Fcons (mod_hooks, hooks);
+	      prev_mod_hooks = mod_hooks;
+	    }
+
+	  i = next_interval (i);
 	}
-
-      i = next_interval (i);
-    }
-  while (! NULL_INTERVAL_P (i) && i->position <= end);
+      /* Keep going thru the interval containing the char before END.  */
+      while (! NULL_INTERVAL_P (i) && i->position < end);
 
-  GCPRO1 (hooks);
-  hooks = Fnreverse (hooks);
-  while (! EQ (hooks, Qnil))
-    {
-      call2 (Fcar (hooks), start, end - 1);
-      hooks = Fcdr (hooks);
+      GCPRO1 (hooks);
+      hooks = Fnreverse (hooks);
+      while (! EQ (hooks, Qnil))
+	{
+	  call_mod_hooks (Fcar (hooks), make_number (start),
+			  make_number (end));
+	  hooks = Fcdr (hooks);
+	}
+      UNGCPRO;
     }
-  UNGCPRO;
 }
 
 /* Balance an interval node if the amount of text in its left and right