diff src/insdel.c @ 21137:f4df45f5a0e2

(combine_bytes): New function. (insert_1_both, insert_from_string_1, insert_from_buffer_1): Simplify greatly by using combine_bytes near the end to handle all aspects of combining except for undo-recording. This means most of the code deals with the text as if there were no combining. (replace_range): Likewise. Also handle unibyte-multibyte conversion as in insert_from_string_1. (del_range_2): Handle combining of character before the deletion with strays after the deletion. (adjust_markers_for_delete): Delete debugging code for Z == Z_BYTE. (adjust_markers_for_insert): Move Z == Z_BYTE debugging code to before we relocate the marker.
author Richard M. Stallman <rms@gnu.org>
date Wed, 11 Mar 1998 22:08:24 +0000
parents be04baf3d970
children 48b83e612b06
line wrap: on
line diff
--- a/src/insdel.c	Wed Mar 11 00:47:48 1998 +0000
+++ b/src/insdel.c	Wed Mar 11 22:08:24 1998 +0000
@@ -368,24 +368,6 @@
 	  m->bytepos = from_byte;
 	}
 
-      /* In a single-byte buffer, a marker's two positions must be equal.  */
-      if (Z == Z_BYTE)
-	{
-	  register int i = m->bytepos;
-
-#if 0
-	  /* We use FROM_BYTE here instead of GPT_BYTE
-	     because FROM_BYTE is where the gap will be after the deletion.  */
-	  if (i > from_byte + coming_gap_size)
-	    i -= coming_gap_size;
-	  else if (i > from_byte)
-	    i = from_byte;
-#endif
-
-	  if (m->charpos != i)
-	    abort ();
-	}
-
       marker = m->chain;
     }
 }
@@ -420,6 +402,17 @@
   while (!NILP (marker))
     {
       register struct Lisp_Marker *m = XMARKER (marker);
+
+      /* In a single-byte buffer, a marker's two positions must be equal.
+	 (If this insertion is going to combine characters, Z will
+	 become different from Z_BYTE, but they might be the same now.
+	 If so, the two OLD positions of the marker should be equal.)  */
+      if (Z == Z_BYTE)
+	{
+	  if (m->charpos != m->bytepos)
+	    abort ();
+	}
+
       if (m->bytepos == from_byte)
 	{
 	  if (m->insertion_type || before_markers)
@@ -465,13 +458,6 @@
 	  m->charpos += nchars;
 	}
 
-      /* In a single-byte buffer, a marker's two positions must be equal.  */
-      if (Z == Z_BYTE)
-	{
-	  if (m->charpos != m->bytepos)
-	    abort ();
-	}
-
       marker = m->chain;
     }
 
@@ -762,7 +748,7 @@
       signal_after_change (opoint, 0, PT - opoint);
     }
 }
-
+
 /* Subroutine used by the insert functions above.  */
 
 void
@@ -774,7 +760,7 @@
   insert_1_both (string, chars_in_text (string, nbytes), nbytes,
 		 inherit, prepare, before_markers);
 }
-
+
 /* See if the bytes before POS/POS_BYTE combine with bytes
    at the start of STRING to form a single character.
    If so, return the number of bytes at the start of STRING
@@ -855,6 +841,34 @@
   return pos_byte - opos_byte;
 }
 
+/* Combine NBYTES stray trailing-codes, which were formerly separate
+   characters, with the preceding character.  These bytes
+   are located after position POS / POS_BYTE, and the preceding character
+   is located just before that position.  */
+
+static void
+combine_bytes (pos, pos_byte, nbytes)
+     int pos, pos_byte, nbytes;
+{
+  /* Adjust all markers.  */
+  adjust_markers_for_delete (pos, pos_byte, pos + nbytes, pos_byte);
+
+  adjust_overlays_for_delete (pos, nbytes);
+
+  if (PT > pos)
+    BUF_PT (current_buffer) -= nbytes;
+  if (GPT > pos)
+    GPT -= nbytes;
+  if (Z > pos)
+    Z -= nbytes;
+  if (ZV > pos)
+    ZV -= nbytes;
+
+  if (BUF_INTERVALS (current_buffer) != 0)
+    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
+    offset_intervals (current_buffer, pos, - nbytes);
+}
+
 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
    starting at STRING.  INHERIT, PREPARE and BEFORE_MARKERS
    are the same as in insert_1.  */
@@ -867,7 +881,6 @@
 {
   register Lisp_Object temp;
   int combined_before_bytes, combined_after_bytes;
-  int adjusted_nchars;
 
   if (NILP (current_buffer->enable_multibyte_characters))
     nchars = nbytes;
@@ -877,17 +890,13 @@
   if (GAP_SIZE < nbytes)
     make_gap (nbytes - GAP_SIZE);
 
-  combined_before_bytes = count_combining_before (string, nbytes, PT, PT_BYTE);
-  combined_after_bytes = count_combining_after (string, nbytes, PT, PT_BYTE);
-
-  /* This is the net amount that Z will increase from this insertion.  */
+  if (prepare)
+    prepare_to_modify_buffer (PT, PT, NULL);
 
-  adjusted_nchars = nchars - combined_before_bytes - combined_after_bytes;
-
-  if (prepare)
-    prepare_to_modify_buffer (PT - !!combined_before_bytes,
-			      PT + combined_after_bytes,
-			      NULL);
+  combined_before_bytes
+    = count_combining_before (string, nbytes, PT, PT_BYTE);
+  combined_after_bytes
+    = count_combining_after (string, nbytes, PT, PT_BYTE);
 
   /* Record deletion of the surrounding text that combines with
      the insertion.  This, together with recording the insertion,
@@ -907,49 +916,52 @@
 
   bcopy (string, GPT_ADDR, nbytes);
 
-#ifdef USE_TEXT_PROPERTIES
-  if (BUF_INTERVALS (current_buffer) != 0)
-    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
-    offset_intervals (current_buffer, PT, adjusted_nchars);
-#endif
-
   GAP_SIZE -= nbytes;
   /* When we have combining at the end of the insertion,
      this is the character position before the combined character.  */
-  GPT += nchars - combined_before_bytes - !!combined_after_bytes;
-  ZV += adjusted_nchars;
-  Z += adjusted_nchars;
+  GPT += nchars;
+  ZV += nchars;
+  Z += nchars;
   GPT_BYTE += nbytes;
   ZV_BYTE += nbytes;
   Z_BYTE += nbytes;
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
-  adjust_overlays_for_insert (PT, adjusted_nchars);
+
+  if (combined_after_bytes)
+    move_gap_both (GPT + combined_after_bytes,
+		   GPT_BYTE + combined_after_bytes);
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  adjust_overlays_for_insert (PT, nchars);
   adjust_markers_for_insert (PT, PT_BYTE,
-			     PT + adjusted_nchars, PT_BYTE + nbytes,
+			     PT + nchars, PT_BYTE + nbytes,
 			     combined_before_bytes, combined_after_bytes,
 			     before_markers);
 
-  /* "Delete" the combined-after bytes, as far as intervals are concerned.
-     Note that as far as the intervals are concerned,
-     no insertion has yet taken place, so these bytes are right after PT.  */
-  if (combined_after_bytes)
-    offset_intervals (current_buffer, PT, - combined_after_bytes);
+#ifdef USE_TEXT_PROPERTIES
+  if (BUF_INTERVALS (current_buffer) != 0)
+    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
+    offset_intervals (current_buffer, PT, nchars);
 
-#ifdef USE_TEXT_PROPERTIES
   if (!inherit && BUF_INTERVALS (current_buffer) != 0)
-    Fset_text_properties (make_number (PT),
-			  make_number (PT + adjusted_nchars + combined_after_bytes),
+    Fset_text_properties (make_number (PT), make_number (PT + nchars),
 			  Qnil, Qnil);
 #endif
 
-  adjust_point (adjusted_nchars + combined_after_bytes,
-		nbytes + combined_after_bytes);
+  {
+    int pos = PT, pos_byte = PT_BYTE;
+
+    adjust_point (nchars + combined_after_bytes,
+		  nbytes + combined_after_bytes);
 
-  if (combined_after_bytes)
-    move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
+    if (combined_after_bytes)
+      combine_bytes (pos + nchars, pos_byte + nbytes, combined_after_bytes);
 
-  if (GPT_BYTE < GPT)
-    abort ();
+    if (combined_before_bytes)
+      combine_bytes (pos, pos_byte, combined_before_bytes);
+  }
 }
 
 /* Insert the part of the text of STRING, a Lisp object assumed to be
@@ -1052,14 +1064,9 @@
      the text that has been stored by copy_text.  */
 
   combined_before_bytes
-    = count_combining_before (XSTRING (string)->data + pos_byte, nbytes,
-			      PT, PT_BYTE);
+    = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
   combined_after_bytes
-    = count_combining_after (XSTRING (string)->data + pos_byte, nbytes,
-			     PT, PT_BYTE);
-
-  /* This is the net amount that Z will increase from this insertion.  */
-  adjusted_nchars = nchars - combined_before_bytes - combined_after_bytes;
+    = count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
 
   /* Record deletion of the surrounding text that combines with
      the insertion.  This, together with recording the insertion,
@@ -1077,49 +1084,54 @@
   record_insert (PT - !!combined_before_bytes, nchars);
   MODIFF++;
 
-  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  offset_intervals (current_buffer, PT, adjusted_nchars);
-
   GAP_SIZE -= outgoing_nbytes;
-  GPT += nchars - combined_before_bytes - !!combined_after_bytes;
-  ZV += adjusted_nchars;
-  Z += adjusted_nchars;
+  GPT += nchars;
+  ZV += nchars;
+  Z += nchars;
   GPT_BYTE += outgoing_nbytes;
   ZV_BYTE += outgoing_nbytes;
   Z_BYTE += outgoing_nbytes;
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
-  adjust_overlays_for_insert (PT, adjusted_nchars);
-  adjust_markers_for_insert (PT, PT_BYTE, PT + adjusted_nchars,
+
+  if (combined_after_bytes)
+    move_gap_both (GPT + combined_after_bytes,
+		   GPT_BYTE + combined_after_bytes);
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  adjust_overlays_for_insert (PT, nchars);
+  adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
 			     PT_BYTE + outgoing_nbytes,
 			     combined_before_bytes, combined_after_bytes,
 			     before_markers);
 
-  if (combined_after_bytes)
-    move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
-
-  if (GPT_BYTE < GPT)
-    abort ();
+  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+  offset_intervals (current_buffer, PT, nchars);
 
-  /* "Delete" the combined-after bytes, as far as intervals are concerned.
-     Note that as far as the intervals are concerned,
-     no insertion has yet taken place, so these bytes are right after PT.  */
-  if (combined_after_bytes)
-    offset_intervals (current_buffer, PT, - combined_after_bytes);
-
+  intervals = XSTRING (string)->intervals;
   /* Get the intervals for the part of the string we are inserting--
      not including the combined-before bytes.  */
-  intervals = XSTRING (string)->intervals;
-  if (combined_before_bytes != 0
-      || nbytes < XSTRING (string)->size_byte)
-    intervals = copy_intervals (intervals, pos + combined_before_bytes,
-				nchars - combined_before_bytes);
+  if (nbytes < XSTRING (string)->size_byte)
+    intervals = copy_intervals (intervals, pos, nchars);
 			       
   /* Insert those intervals.  */
-  graft_intervals_into_buffer (intervals, PT, nchars - combined_before_bytes,
+  graft_intervals_into_buffer (intervals, PT, nchars,
 			       current_buffer, inherit);
 
-  adjust_point (adjusted_nchars + combined_after_bytes,
-		outgoing_nbytes + combined_after_bytes);
+  {
+    int pos = PT, pos_byte = PT_BYTE;
+
+    adjust_point (nchars + combined_after_bytes,
+		  outgoing_nbytes + combined_after_bytes);
+
+    if (combined_after_bytes)
+      combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
+		     combined_after_bytes);
+
+    if (combined_before_bytes)
+      combine_bytes (pos, pos_byte, combined_before_bytes);
+  }
 }
 
 /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
@@ -1203,17 +1215,14 @@
   /* We have copied text into the gap, but we have not altered
      PT or PT_BYTE yet.  So we can pass PT and PT_BYTE
      to these functions and get the same results as we would
-     have got earlier on.  Meanwhile, PT_ADDR does point to
+     have got earlier on.  Meanwhile, GPT_ADDR does point to
      the text that has been stored by copy_text.  */
   combined_before_bytes
-    = count_combining_before (PT_ADDR, outgoing_nbytes, PT, PT_BYTE);
+    = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
   combined_after_bytes
-    = count_combining_after (PT_ADDR, outgoing_nbytes,
+    = count_combining_after (GPT_ADDR, outgoing_nbytes,
 			     PT, PT_BYTE);
 
-  /* This is the net amount that Z will increase from this insertion.  */
-  adjusted_nchars = nchars - combined_before_bytes - combined_after_bytes;
-
   /* Record deletion of the surrounding text that combines with
      the insertion.  This, together with recording the insertion,
      will add up to the right stuff in the undo list.
@@ -1230,51 +1239,54 @@
   record_insert (PT - !!combined_before_bytes, nchars);
   MODIFF++;
 
-#ifdef USE_TEXT_PROPERTIES
-  if (BUF_INTERVALS (current_buffer) != 0)
-    offset_intervals (current_buffer, PT, adjusted_nchars);
-#endif
-
   GAP_SIZE -= outgoing_nbytes;
-  GPT += nchars - combined_before_bytes - !!combined_after_bytes;
-  ZV += adjusted_nchars;
-  Z += adjusted_nchars;
+  GPT += nchars;
+  ZV += nchars;
+  Z += nchars;
   GPT_BYTE += outgoing_nbytes;
   ZV_BYTE += outgoing_nbytes;
   Z_BYTE += outgoing_nbytes;
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
-  adjust_overlays_for_insert (PT, adjusted_nchars);
-  adjust_markers_for_insert (PT, PT_BYTE, PT + adjusted_nchars,
+
+  if (combined_after_bytes)
+    move_gap_both (GPT + combined_after_bytes,
+		   GPT_BYTE + combined_after_bytes);
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  adjust_overlays_for_insert (PT, nchars);
+  adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
 			     PT_BYTE + outgoing_nbytes,
 			     combined_before_bytes, combined_after_bytes, 0);
 
-  /* "Delete" the combined-after bytes, as far as intervals are concerned.
-     Note that as far as the intervals are concerned,
-     no insertion has yet taken place, so these bytes are right after PT.  */
-  if (combined_after_bytes)
-    offset_intervals (current_buffer, PT, - combined_after_bytes);
+#ifdef USE_TEXT_PROPERTIES
+  if (BUF_INTERVALS (current_buffer) != 0)
+    offset_intervals (current_buffer, PT, nchars);
+#endif
 
   /* Get the intervals for the part of the string we are inserting--
      not including the combined-before bytes.  */
   intervals = BUF_INTERVALS (buf);
-  if (combined_before_bytes != 0
-      || nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
-    intervals = copy_intervals (intervals, from + combined_before_bytes,
-				nchars - combined_before_bytes);
+  if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
+    intervals = copy_intervals (intervals, from, nchars);
 			       
   /* Insert those intervals.  */
-  graft_intervals_into_buffer (intervals, PT, nchars - combined_before_bytes,
-			       current_buffer, inherit);
+  graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
 
+  {
+    int pos = PT, pos_byte = PT_BYTE;
+
+    adjust_point (nchars + combined_after_bytes,
+		  outgoing_nbytes + combined_after_bytes);
 
-  adjust_point (adjusted_nchars + combined_after_bytes,
-		outgoing_nbytes + combined_after_bytes);
+    if (combined_after_bytes)
+      combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
+		     combined_after_bytes);
 
-  if (combined_after_bytes)
-    move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
-
-  if (GPT_BYTE < GPT)
-    abort ();
+    if (combined_before_bytes)
+      combine_bytes (pos, pos_byte, combined_before_bytes);
+  }
 }
 
 /* This function should be called after moving gap to FROM and before
@@ -1344,6 +1356,7 @@
   int combined_before_bytes, combined_after_bytes;
   int adjusted_inschars;
   INTERVAL intervals;
+  int outgoing_insbytes = insbytes;
 
   GCPRO1 (new);
 
@@ -1371,6 +1384,15 @@
   if (nbytes_del <= 0 && insbytes == 0)
     return;
 
+  /* Make OUTGOING_INSBYTES describe the text
+     as it will be inserted in this buffer.  */
+
+  if (NILP (current_buffer->enable_multibyte_characters))
+    outgoing_insbytes = inschars;
+  else if (inschars == insbytes)
+    outgoing_insbytes
+      = count_size_as_multibyte (XSTRING (new)->data, insbytes);
+
   /* Make sure point-max won't overflow after this insertion.  */
   XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
   if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
@@ -1412,20 +1434,26 @@
   if (GAP_SIZE < insbytes)
     make_gap (insbytes - GAP_SIZE);
 
+  /* Copy the string text into the buffer, perhaps converting
+     between single-byte and multibyte.  */
+  copy_text (XSTRING (new)->data, GPT_ADDR, insbytes,
+	     /* If these are equal, it is a single-byte string.
+		Its chars are either ASCII, in which case copy_text
+		won't change it, or single-byte non-ASCII chars,
+		that need to be changed.  */
+	     inschars != insbytes,
+	     ! NILP (current_buffer->enable_multibyte_characters));
+
   /* We have copied text into the gap, but we have not altered
      PT or PT_BYTE yet.  So we can pass PT and PT_BYTE
      to these functions and get the same results as we would
-     have got earlier on.  Meanwhile, PT_ADDR does point to
+     have got earlier on.  Meanwhile, GPT_ADDR does point to
      the text that has been stored by copy_text.  */
 
   combined_before_bytes
-    = count_combining_before (XSTRING (new)->data, insbytes, PT, PT_BYTE);
+    = count_combining_before (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
   combined_after_bytes
-    = count_combining_after (XSTRING (new)->data, insbytes, PT, PT_BYTE);
-
-  /* This is the net amount that Z will increase from this insertion.  */
-  adjusted_inschars
-    = inschars - combined_before_bytes - combined_after_bytes;
+    = count_combining_after (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
 
   /* Record deletion of the surrounding text that combines with
      the insertion.  This, together with recording the insertion,
@@ -1442,28 +1470,18 @@
 
   record_insert (from, inschars);
 
-  bcopy (XSTRING (new)->data, GPT_ADDR, insbytes);
-
-  /* Relocate point as if it were a marker.  */
-  if (from < PT)
-    adjust_point ((from + adjusted_inschars - (PT < to ? PT : to)
-		   + combined_after_bytes),
-		  (from_byte + insbytes
-		   - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
-		   + combined_after_bytes));
+  GAP_SIZE -= outgoing_insbytes;
+  GPT += inschars;
+  ZV += inschars;
+  Z += inschars;
+  GPT_BYTE += outgoing_insbytes;
+  ZV_BYTE += outgoing_insbytes;
+  Z_BYTE += outgoing_insbytes;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
 
-#ifdef USE_TEXT_PROPERTIES
-  offset_intervals (current_buffer, PT, adjusted_inschars - nchars_del);
-#endif
-
-  GAP_SIZE -= insbytes;
-  GPT += inschars - combined_before_bytes - !!combined_after_bytes;
-  ZV += adjusted_inschars;
-  Z += adjusted_inschars;
-  GPT_BYTE += insbytes;
-  ZV_BYTE += insbytes;
-  ZV_BYTE += insbytes;
-  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
+  if (combined_after_bytes)
+    move_gap_both (GPT + combined_after_bytes,
+		   GPT_BYTE + combined_after_bytes);
 
   if (GPT_BYTE < GPT)
     abort ();
@@ -1471,39 +1489,44 @@
   /* Adjust the overlay center as needed.  This must be done after
      adjusting the markers that bound the overlays.  */
   adjust_overlays_for_delete (from, nchars_del);
-  adjust_overlays_for_insert (from, adjusted_inschars);
-  adjust_markers_for_insert (from, from_byte, from + adjusted_inschars,
-			     from_byte + insbytes,
+  adjust_overlays_for_insert (from, inschars);
+  adjust_markers_for_insert (from, from_byte,
+			     from + inschars, from_byte + outgoing_insbytes,
 			     combined_before_bytes, combined_after_bytes, 0);
 
-  /* "Delete" the combined-after bytes, as far as intervals are concerned.
-     Note that as far as the intervals are concerned,
-     no insertion has yet taken place, so these bytes are right after PT.  */
-  if (combined_after_bytes)
-    offset_intervals (current_buffer, PT, - combined_after_bytes);
+#ifdef USE_TEXT_PROPERTIES
+  offset_intervals (current_buffer, PT, inschars - nchars_del);
 
   /* Get the intervals for the part of the string we are inserting--
      not including the combined-before bytes.  */
   intervals = XSTRING (new)->intervals;
-  if (combined_before_bytes != 0)
-    intervals = copy_intervals (intervals, combined_before_bytes,
-				inschars - combined_before_bytes);
-			       
   /* Insert those intervals.  */
-  graft_intervals_into_buffer (intervals, from,
-			       inschars - combined_before_bytes,
+  graft_intervals_into_buffer (intervals, from, inschars,
 			       current_buffer, inherit);
+#endif
 
-  if (insbytes == 0)
-    evaporate_overlays (from);
+  /* Relocate point as if it were a marker.  */
+  if (from < PT)
+    adjust_point ((from + inschars - (PT < to ? PT : to)
+		   + combined_after_bytes),
+		  (from_byte + outgoing_insbytes
+		   - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
+		   + combined_after_bytes));
 
   if (combined_after_bytes)
-    move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
+    combine_bytes (from + inschars, from_byte + outgoing_insbytes,
+		   combined_after_bytes);
+
+  if (combined_before_bytes)
+    combine_bytes (from, from_byte, combined_before_bytes);
+
+  if (outgoing_insbytes == 0)
+    evaporate_overlays (from);
 
   MODIFF++;
   UNGCPRO;
 
-  signal_after_change (from, nchars_del, adjusted_inschars);
+  signal_after_change (from, nchars_del, PT - from);
 }
 
 /* Delete characters in current buffer
@@ -1629,6 +1652,7 @@
      int from, from_byte, to, to_byte;
 {
   register int nbytes_del, nchars_del;
+  int combined_after_bytes;
 
   nchars_del = to - from;
   nbytes_del = to_byte - from_byte;
@@ -1677,6 +1701,16 @@
   if (Z - GPT < end_unchanged)
     end_unchanged = Z - GPT;
 
+  combined_after_bytes
+    = count_combining_before (GAP_END_ADDR, ZV_BYTE - GPT_BYTE, PT, PT_BYTE);
+
+  if (combined_after_bytes)
+    move_gap_both (GPT + combined_after_bytes,
+		   GPT_BYTE + combined_after_bytes);
+
+  if (combined_after_bytes)
+    combine_bytes (PT, PT_BYTE, combined_after_bytes);
+
   evaporate_overlays (from);
   signal_after_change (from, nchars_del, 0);
 }