(signal_before_change): If inhibit_modification_hooks
[bpt/emacs.git] / src / insdel.c
index 80e9d78..a7807dd 100644 (file)
@@ -400,6 +400,45 @@ adjust_markers_for_delete (from, from_byte, to, to_byte)
       marker = m->chain;
     }
 }
+
+/* Adjust all markers for a byte combining of NBYTES at char position
+   FROM and byte position FROM_BYTE.  */
+
+static void
+adjust_markers_for_combining (from, from_byte, nbytes)
+     register int from, from_byte, nbytes;
+{
+  Lisp_Object marker;
+  register struct Lisp_Marker *m;
+  register int bytepos;
+  register int to_byte = from_byte + nbytes;
+
+  marker = BUF_MARKERS (current_buffer);
+
+  while (!NILP (marker))
+    {
+      m = XMARKER (marker);
+      bytepos = m->bytepos;
+
+      if (bytepos >= to_byte)
+       {
+         record_marker_adjustment (marker,  - nbytes);
+         m->charpos -= nbytes;
+       }
+      else if (bytepos > from_byte)
+       {
+         record_marker_adjustment (marker,  from - m->charpos);
+         m->charpos = from;
+         m->bytepos = to_byte;
+       }
+      else if (bytepos == from_byte)
+       {
+         m->bytepos = to_byte;
+       }
+
+      marker = m->chain;
+    }
+}
 \f
 /* Adjust all markers for calling record_delete for combining bytes.
    whose range in bytes is FROM_BYTE to TO_BYTE.
@@ -595,14 +634,6 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
          m->charpos = from;
          m->bytepos = from_byte;
        }
-      else if (m->bytepos == from_byte)
-       {
-         if (combined_before_bytes)
-           {
-             DEC_BOTH (m->charpos, m->bytepos);
-             INC_BOTH (m->charpos, m->bytepos);
-           }
-       }
 
       marker = m->chain;
     }
@@ -717,18 +748,7 @@ copy_text (from_addr, to_addr, nbytes,
          int thislen, c, c_save;
          c = c_save = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
          if (!SINGLE_BYTE_CHAR_P (c))
-           {
-             if (!NILP (tbl))
-               {
-                 temp = Faref (tbl, make_number (c));
-                 if (INTEGERP (temp))
-                   c = XINT (temp);
-               }
-             else if (nonascii_insert_offset > 0)
-               c -= nonascii_insert_offset;
-             if (c < 128 || c >= 256)
-               c = (c_save & 0177) + 0200;
-           }
+           c = multibyte_char_to_unibyte (c, tbl);
          *to_addr++ = c;
          from_addr += thislen;
          bytes_left -= thislen;
@@ -747,7 +767,7 @@ copy_text (from_addr, to_addr, nbytes,
          unsigned char workbuf[4], *str;
          int len;
 
-         if (c >= 0240 && c < 0400)
+         if ((c >= 0240 || !NILP (Vnonascii_translation_table)) && c < 0400)
            {
              c = unibyte_char_to_multibyte (c);
              len = CHAR_STRING (c, workbuf, str);
@@ -779,12 +799,12 @@ count_size_as_multibyte (ptr, nbytes)
     {
       unsigned int c = *ptr++;
 
-      if (c < 0240)
+      if (c < 0240 && NILP (Vnonascii_translation_table))
        outgoing_nbytes++;
       else
        {
          c = unibyte_char_to_multibyte (c);
-         outgoing_nbytes += XINT (Fchar_bytes (make_number (c)));
+         outgoing_nbytes += CHAR_BYTES (c);
        }
     }
 
@@ -961,11 +981,23 @@ count_combining_after (string, length, pos, pos_byte)
   if (length == 0 || ASCII_BYTE_P (string[length - 1]))
     return 0;
   i = length - 1;
-  while (i > 0 && ! CHAR_HEAD_P (string[i]))
+  while (i >= 0 && ! CHAR_HEAD_P (string[i]))
     {
       i--;
     }
-  if (! BASE_LEADING_CODE_P (string[i]))
+  if (i < 0)
+    {
+      /* All characters in `string' are not character head.
+        We must check also preceding bytes at POS.
+        We are sure that the gap is at POS.  */
+      string = BEG_ADDR;
+      i = pos_byte - 2;
+      while (i >= 0 && ! CHAR_HEAD_P (string[i]))
+       i--;
+      if (i < 0 || !BASE_LEADING_CODE_P (string[i]))
+       return 0;
+    }
+  else if (!BASE_LEADING_CODE_P (string[i]))
     return 0;
 
   if (pos == ZV)
@@ -1012,7 +1044,7 @@ 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_markers_for_combining (pos, pos_byte, nbytes);
 
   adjust_overlays_for_delete (pos, nbytes);
 
@@ -1575,7 +1607,7 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
                                        from_byte + combined_after_bytes);
 
       if (! EQ (current_buffer->undo_list, Qt))
-       record_delete (from, deletion);
+       record_delete (from + len, deletion);
     }
 
   if (combined_before_bytes)
@@ -1612,7 +1644,7 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
                              len, len_byte,
                              combined_before_bytes, combined_after_bytes);
   if (STRINGP (prev_text))
-    record_delete (from, prev_text);
+    record_delete (from - !!combined_before_bytes, prev_text);
   record_insert (from - !!combined_before_bytes,
                 len - combined_before_bytes + !!combined_before_bytes);
 
@@ -1622,20 +1654,25 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
     adjust_overlays_for_delete (from, nchars_del - len);
 #ifdef USE_TEXT_PROPERTIES
   if (BUF_INTERVALS (current_buffer) != 0)
-    offset_intervals (current_buffer, from, len - nchars_del);
+    {
+      offset_intervals (current_buffer, from, len - nchars_del);
+    }
 #endif
 
   {
     int pos = PT, pos_byte = PT_BYTE;
 
     if (from < PT)
-      adjust_point (len - nchars_del + combined_after_bytes,
-                   len_byte - nbytes_del + combined_after_bytes);
-    else if (from == PT && combined_before_bytes)
-      adjust_point (0, combined_before_bytes);
+      adjust_point (len - nchars_del, len_byte - nbytes_del);
 
     if (combined_after_bytes)
-      combine_bytes (from + len, from_byte + len_byte, combined_after_bytes);
+      {
+       if (combined_before_bytes)
+         combined_before_bytes += combined_after_bytes;
+       else
+         combine_bytes (from + len, from_byte + len_byte,
+                        combined_after_bytes);
+      }
 
     if (combined_before_bytes)
       combine_bytes (from, from_byte, combined_before_bytes);
@@ -1676,12 +1713,14 @@ adjust_after_insert (from, from_byte, to, to_byte, newlen)
 /* 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.  */
+   That way, undo will also handle markers properly.
+
+   But if MARKERS is 0, don't relocate markers.  */
 
 void
-replace_range (from, to, new, prepare, inherit, nomarkers)
+replace_range (from, to, new, prepare, inherit, markers)
      Lisp_Object new;
-     int from, to, prepare, inherit, nomarkers;
+     int from, to, prepare, inherit, markers;
 {
   int inschars = XSTRING (new)->size;
   int insbytes = STRING_BYTES (XSTRING (new));
@@ -1693,6 +1732,7 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
   int adjusted_inschars;
   INTERVAL intervals;
   int outgoing_insbytes = insbytes;
+  Lisp_Object deletion;
 
   CHECK_MARKERS ();
 
@@ -1744,23 +1784,17 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
   if (to < GPT)
     gap_left (to, to_byte, 0);
 
-  {
-    Lisp_Object deletion;
-    deletion = Qnil;
+  deletion = Qnil;
 
-    if (! EQ (current_buffer->undo_list, Qt))
-      deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
-
-    if (nomarkers)
-      /* Relocate all markers pointing into the new, larger gap
-        to point at the end of the text before the gap.
-        Do this before recording the deletion,
-        so that undo handles this after reinserting the text.  */
-      adjust_markers_for_delete (from, from_byte, to, to_byte);
+  if (! EQ (current_buffer->undo_list, Qt))
+    deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
 
-    if (! EQ (current_buffer->undo_list, Qt))
-      record_delete (from, deletion);
-  }
+  if (markers)
+    /* Relocate all markers pointing into the new, larger gap
+       to point at the end of the text before the gap.
+       Do this before recording the deletion,
+       so that undo handles this after reinserting the text.  */
+    adjust_markers_for_delete (from, from_byte, to, to_byte);
 
   GAP_SIZE += nbytes_del;
   ZV -= nchars_del;
@@ -1788,16 +1822,16 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
             STRING_MULTIBYTE (new),
             ! 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, GPT_ADDR does point to
+  /* We have copied text into the gap, but we have not marked
+     it as part of the buffer.  So we can use the old FROM and FROM_BYTE
+     here, for both the previous text and the following text.
+     Meanwhile, GPT_ADDR does point to
      the text that has been stored by copy_text.  */
 
   combined_before_bytes
-    = count_combining_before (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
+    = count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte);
   combined_after_bytes
-    = count_combining_after (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
+    = count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte);
 
   /* Record deletion of the surrounding text that combines with
      the insertion.  This, together with recording the insertion,
@@ -1812,15 +1846,15 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
       deletion = Qnil;
 
       if (! EQ (current_buffer->undo_list, Qt))
-       deletion = make_buffer_string_both (PT, PT_BYTE,
-                                           PT + combined_after_bytes,
-                                           PT_BYTE + combined_after_bytes, 1);
+       deletion = make_buffer_string_both (from, from_byte,
+                                           from + combined_after_bytes,
+                                           from_byte + combined_after_bytes, 1);
 
-      adjust_markers_for_record_delete (PT, PT_BYTE,
-                                       PT + combined_after_bytes,
-                                       PT_BYTE + combined_after_bytes);
+      adjust_markers_for_record_delete (from, from_byte,
+                                       from + combined_after_bytes,
+                                       from_byte + combined_after_bytes);
       if (! EQ (current_buffer->undo_list, Qt))
-       record_delete (PT, deletion);
+       record_delete (from + inschars, deletion);
     }
 
   if (combined_before_bytes)
@@ -1829,16 +1863,21 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
       deletion = Qnil;
 
       if (! EQ (current_buffer->undo_list, Qt))
-       deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
-                                           PT, PT_BYTE, 1);
-      adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
-                                       PT, PT_BYTE);
+       deletion = make_buffer_string_both (from - 1, CHAR_TO_BYTE (from - 1),
+                                           from, from_byte, 1);
+      adjust_markers_for_record_delete (from - 1, CHAR_TO_BYTE (from - 1),
+                                       from, from_byte);
       if (! EQ (current_buffer->undo_list, Qt))
-       record_delete (PT - 1, deletion);
+       record_delete (from - 1, deletion);
     }
 
-  record_insert (PT - !!combined_before_bytes,
-                inschars - combined_before_bytes + !!combined_before_bytes);
+  if (! EQ (current_buffer->undo_list, Qt))
+    {
+      record_delete (from - !!combined_before_bytes, deletion);
+      record_insert (from - !!combined_before_bytes,
+                    (inschars - combined_before_bytes
+                     + !!combined_before_bytes));
+    }
 
   GAP_SIZE -= outgoing_insbytes;
   GPT += inschars;
@@ -1860,13 +1899,13 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
      adjusting the markers that bound the overlays.  */
   adjust_overlays_for_delete (from, nchars_del);
   adjust_overlays_for_insert (from, inschars);
-  if (nomarkers)
+  if (markers)
     adjust_markers_for_insert (from, from_byte,
                               from + inschars, from_byte + outgoing_insbytes,
                               combined_before_bytes, combined_after_bytes, 0);
 
 #ifdef USE_TEXT_PROPERTIES
-  offset_intervals (current_buffer, PT, inschars - nchars_del);
+  offset_intervals (current_buffer, from, inschars - nchars_del);
 
   /* Get the intervals for the part of the string we are inserting--
      not including the combined-before bytes.  */
@@ -1878,16 +1917,18 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
 
   /* Relocate point as if it were a marker.  */
   if (from < PT)
-    adjust_point ((from + inschars - (PT < to ? PT : to)
-                  + combined_after_bytes),
+    adjust_point ((from + inschars - (PT < to ? PT : to)),
                  (from_byte + outgoing_insbytes
-                  - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
-                  + combined_after_bytes));
+                  - (PT_BYTE < to_byte ? PT_BYTE : to_byte)));
 
   if (combined_after_bytes)
-    combine_bytes (from + inschars, from_byte + outgoing_insbytes,
-                  combined_after_bytes);
-
+    {
+      if (combined_before_bytes)
+       combined_before_bytes += combined_after_bytes;
+      else
+       combine_bytes (from + inschars, from_byte + outgoing_insbytes,
+                      combined_after_bytes);
+    }
   if (combined_before_bytes)
     combine_bytes (from, from_byte, combined_before_bytes);
 
@@ -1899,7 +1940,7 @@ replace_range (from, to, new, prepare, inherit, nomarkers)
   MODIFF++;
   UNGCPRO;
 
-  signal_after_change (from, nchars_del, PT - from);
+  signal_after_change (from, nchars_del, GPT - from);
 }
 \f
 /* Delete characters in current buffer
@@ -2279,6 +2320,9 @@ signal_before_change (start_int, end_int, preserve_ptr)
   Lisp_Object preserve_marker;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
+  if (inhibit_modification_hooks)
+    return;
+
   start = make_number (start_int);
   end = make_number (end_int);
   preserve_marker = Qnil;
@@ -2365,6 +2409,9 @@ void
 signal_after_change (charpos, lendel, lenins)
      int charpos, lendel, lenins;
 {
+  if (inhibit_modification_hooks)
+    return;
+
   /* 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.  */