changeset 72272:f3b2e3e20e3b

(Fsubst_char_in_region): Redo the setup work after running the before-change-functions since they may have altered the buffer.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Fri, 04 Aug 2006 15:22:09 +0000
parents 792164bfdf71
children 3f5cb3f04fdc
files src/ChangeLog src/editfns.c
diffstat 2 files changed, 24 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Fri Aug 04 11:43:45 2006 +0000
+++ b/src/ChangeLog	Fri Aug 04 15:22:09 2006 +0000
@@ -1,3 +1,8 @@
+2006-08-04  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+	* editfns.c (Fsubst_char_in_region): Redo the setup work after running
+	the before-change-functions since they may have altered the buffer.
+
 2006-08-04  Ralf Angeli  <angeli@caeruleus.net>
 
 	* w32fns.c (w32_createwindow): Handle -geometry command line option
--- a/src/editfns.c	Fri Aug 04 11:43:45 2006 +0000
+++ b/src/editfns.c	Fri Aug 04 15:22:09 2006 +0000
@@ -2691,6 +2691,10 @@
      Lisp_Object start, end, fromchar, tochar, noundo;
 {
   register int pos, pos_byte, stop, i, len, end_byte;
+  /* Keep track of the first change in the buffer:
+     if 0 we haven't found it yet.
+     if < 0 we've found it and we've run the before-change-function.
+     if > 0 we've actually performed it and the value is its position.  */
   int changed = 0;
   unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
   unsigned char *p;
@@ -2703,6 +2707,8 @@
   int last_changed = 0;
   int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
+ restart:
+
   validate_region (&start, &end);
   CHECK_NUMBER (fromchar);
   CHECK_NUMBER (tochar);
@@ -2740,7 +2746,7 @@
      That's faster than getting rid of things,
      and it prevents even the entry for a first change.
      Also inhibit locking the file.  */
-  if (!NILP (noundo))
+  if (!changed && !NILP (noundo))
     {
       record_unwind_protect (subst_char_in_region_unwind,
 			     current_buffer->undo_list);
@@ -2774,10 +2780,14 @@
 		  && (len == 2 || (p[2] == fromstr[2]
 				 && (len == 3 || p[3] == fromstr[3]))))))
 	{
-	  if (! changed)
+	  if (changed < 0)
+	    /* We've already seen this and run the before-change-function;
+	       this time we only need to record the actual position. */
+	    changed = pos;
+	  else if (!changed)
 	    {
-	      changed = pos;
-	      modify_region (current_buffer, changed, XINT (end));
+	      changed = -1;
+	      modify_region (current_buffer, pos, XINT (end));
 
 	      if (! NILP (noundo))
 		{
@@ -2786,6 +2796,10 @@
 		  if (MODIFF - 1 == current_buffer->auto_save_modified)
 		    current_buffer->auto_save_modified++;
 		}
+
+	      /* The before-change-function may have moved the gap
+		 or even modified the buffer so we should start over. */
+	      goto restart;
 	    }
 
 	  /* Take care of the case where the new character
@@ -2838,7 +2852,7 @@
       pos++;
     }
 
-  if (changed)
+  if (changed > 0)
     {
       signal_after_change (changed,
 			   last_changed - changed, last_changed - changed);