(display_prop_end, invisible_text_between_p): Use
[bpt/emacs.git] / src / insdel.c
index 87f0a78..b4f6ac5 100644 (file)
@@ -20,6 +20,9 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
@@ -33,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 #define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
 
 static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int));
 static void insert_from_buffer_1 ();
@@ -77,7 +81,7 @@ static int check_markers_debug_flag;
 void
 check_markers ()
 {
-  register Lisp_Object tail, prev, next;
+  register Lisp_Object tail;
   int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
 
   tail = BUF_MARKERS (current_buffer);
@@ -135,21 +139,7 @@ gap_left (charpos, bytepos, newgap)
   int new_s1;
 
   if (!newgap)
-    {
-      if (unchanged_modified == MODIFF
-         && overlay_unchanged_modified == OVERLAY_MODIFF)
-       {
-         beg_unchanged = charpos - BEG;
-         end_unchanged = Z - charpos;
-       }
-      else
-       {
-         if (Z - GPT < end_unchanged)
-           end_unchanged = Z - GPT;
-         if (charpos < beg_unchanged)
-           beg_unchanged = charpos - BEG;
-       }
-    }
+    BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
 
   i = GPT_BYTE;
   to = GAP_END_ADDR;
@@ -224,19 +214,7 @@ gap_right (charpos, bytepos)
   register int i;
   int new_s1;
 
-  if (unchanged_modified == MODIFF
-      && overlay_unchanged_modified == OVERLAY_MODIFF)
-    {
-      beg_unchanged = charpos - BEG;
-      end_unchanged = Z - charpos;
-    }
-  else
-    {
-      if (Z - charpos - 1 < end_unchanged)
-       end_unchanged = Z - charpos;
-      if (GPT - BEG < beg_unchanged)
-       beg_unchanged = GPT - BEG;
-    }
+  BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
 
   i = GPT_BYTE;
   from = GAP_END_ADDR;
@@ -578,7 +556,12 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
     {
       register struct Lisp_Marker *m = XMARKER (marker);
 
-      if (m->bytepos >= prev_to_byte)
+      if (m->bytepos >= prev_to_byte
+         && (old_bytes != 0
+             /* If this is an insertion (replacing 0 chars),
+                reject the case of a marker that is at the
+                insertion point and should stay before the insertion.  */
+             || m->bytepos > from_byte || m->insertion_type))
        {
          if (m->bytepos < prev_to_byte + combined_after_bytes)
            {
@@ -700,7 +683,7 @@ copy_text (from_addr, to_addr, nbytes,
     {
       int nchars = 0;
       int bytes_left = nbytes;
-      Lisp_Object tbl = Qnil, temp;
+      Lisp_Object tbl = Qnil;
 
       /* We set the variable tbl to the reverse table of
          Vnonascii_translation_table in advance.  */
@@ -896,6 +879,33 @@ insert_1 (string, nbytes, inherit, prepare, before_markers)
                 inherit, prepare, before_markers);
 }
 \f
+/* See if the byte sequence at STR1 of length LEN1 combine with the
+   byte sequence at STR2 of length LEN2 to form a single composite
+   character.  If so, return the number of bytes at the start of STR2
+   which combine in this way.  Otherwise, return 0.  If STR3 is not
+   NULL, it is a byte sequence of length LEN3 to be appended to STR1
+   before checking the combining.  */
+int
+count_combining_composition (str1, len1, str2, len2, str3, len3)
+     unsigned char *str1, *str2, *str3;
+     int len1, len2, len3;
+{
+  int len = len1 + len2 + len3;
+  unsigned char *buf = (unsigned char *) alloca (len + 1);
+  int bytes;
+
+  bcopy (str1, buf, len1);
+  if (str3)
+    {
+      bcopy (str3, buf + len1, len3);
+      len1 += len3;
+    }
+  bcopy (str2, buf + len1 , len2);
+  buf[len] = 0;
+  PARSE_MULTIBYTE_SEQ (buf, len, bytes);
+  return (bytes <= len1 ? 0 : bytes - len1);
+}
+
 /* 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
@@ -907,30 +917,44 @@ count_combining_before (string, length, pos, pos_byte)
      int length;
      int pos, pos_byte;
 {
-  int opos = pos, opos_byte = pos_byte;
-  int c;
-  unsigned char *p = string;
+  int len, combining_bytes;
+  unsigned char *p;
 
   if (NILP (current_buffer->enable_multibyte_characters))
     return 0;
-  if (length == 0 || CHAR_HEAD_P (*string))
+
+  /* At first, we can exclude the following cases:
+       (1) STRING[0] can't be a following byte of multibyte sequence.
+       (2) POS is the start of the current buffer.
+       (3) A character before POS is not a multibyte character.  */
+  if (length == 0 || CHAR_HEAD_P (*string)) /* case (1) */
     return 0;
-  if (pos == BEG)
+  if (pos_byte == BEG_BYTE)    /* case (2) */
     return 0;
-  c = FETCH_BYTE (pos_byte - 1);
-  if (ASCII_BYTE_P (c))
+  len = 1;
+  p = BYTE_POS_ADDR (pos_byte - 1);
+  while (! CHAR_HEAD_P (*p)) p--, len++;
+  if (! BASE_LEADING_CODE_P (*p)) /* case (3) */
     return 0;
-  DEC_BOTH (pos, pos_byte);
-  c = FETCH_BYTE (pos_byte);
-  if (! BASE_LEADING_CODE_P (c))
+
+  /* A sequence of a composite character requires a special handling.  */
+  if (*p == LEADING_CODE_COMPOSITION)
+    return count_combining_composition (p, len, string, length, NULL, 0);
+
+  combining_bytes = BYTES_BY_CHAR_HEAD (*p) - len;
+  if (combining_bytes <= 0)
+    /* The character preceding POS is, complete and no room for
+       combining bytes (combining_bytes == 0), or an independent 8-bit
+       character (combining_bytes < 0).  */
     return 0;
 
-  /* We have a combination situation.
-     Count the bytes at STRING that will combine.  */
+  /* We have a combination situation.  Count the bytes at STRING that
+     may combine.  */
+  p = string + 1;
   while (!CHAR_HEAD_P (*p) && p < string + length)
     p++;
 
-  return p - string;
+  return (combining_bytes < p - string ? combining_bytes : p - string);
 }
 
 /* See if the bytes after POS/POS_BYTE combine with bytes
@@ -944,14 +968,27 @@ count_combining_after (string, length, pos, pos_byte)
      int length;
      int pos, pos_byte;
 {
-  int opos = pos, opos_byte = pos_byte;
+  int opos_byte = pos_byte;
   int i;
-  int c;
+  int bytes;
+  unsigned char *bufp;
 
   if (NILP (current_buffer->enable_multibyte_characters))
     return 0;
-  if (length > 0 && ASCII_BYTE_P (string[length - 1]))
+
+  /* At first, we can exclude the following cases:
+       (1) The last byte of STRING is an ASCII.
+       (2) POS is the last of the current buffer.
+       (3) A character at POS can't be a following byte of multibyte
+           character.  */
+  if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */
+    return 0;
+  if (pos_byte == Z_BYTE)      /* case (2) */
     return 0;
+  bufp = BYTE_POS_ADDR (pos_byte);
+  if (CHAR_HEAD_P (*bufp))     /* case (3) */
+    return 0;
+
   i = length - 1;
   while (i >= 0 && ! CHAR_HEAD_P (string[i]))
     {
@@ -959,33 +996,37 @@ count_combining_after (string, length, pos, pos_byte)
     }
   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;
+      /* 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.  */
+      unsigned char *p = BEG_ADDR;
       i = pos_byte - 2;
-      while (i >= 0 && ! CHAR_HEAD_P (string[i]))
+      while (i >= 0 && ! CHAR_HEAD_P (p[i]))
        i--;
-      if (i < 0 || !BASE_LEADING_CODE_P (string[i]))
+      if (i < 0 || !BASE_LEADING_CODE_P (p[i]))
        return 0;
+      /* A sequence of a composite character requires a special handling.  */
+      if (p[i] == LEADING_CODE_COMPOSITION)
+       return count_combining_composition (p + i, pos_byte - 1 - i,
+                                           bufp, Z_BYTE - pos_byte,
+                                           string, length);
+      bytes = BYTES_BY_CHAR_HEAD (p[i]);
+      return (bytes <= pos_byte - 1 - i + length
+             ? 0
+             : bytes - (pos_byte - 1 - i + length));
     }
-  else if (!BASE_LEADING_CODE_P (string[i]))
+  if (!BASE_LEADING_CODE_P (string[i]))
     return 0;
+  /* A sequence of a composite character requires a special handling.  */
+  if (string[i] == LEADING_CODE_COMPOSITION)
+    return count_combining_composition (string + i, length - i,
+                                       bufp, Z_BYTE - pos_byte, NULL, 0);
 
-  if (pos == Z)
-    return 0;
-  c = FETCH_BYTE (pos_byte);
-  if (CHAR_HEAD_P (c))
-    return 0;
-  while (pos_byte < Z_BYTE)
-    {
-      c = FETCH_BYTE (pos_byte);
-      if (CHAR_HEAD_P (c))
-       break;
-      pos_byte++;
-    }
+  bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
+  bufp++, pos_byte++;
+  while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
 
-  return pos_byte - opos_byte;
+  return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
 }
 
 /* Adjust the position TARGET/TARGET_BYTE for the combining of NBYTES
@@ -1041,8 +1082,8 @@ byte_combining_error ()
    region boundary, signal an error.  */
 #define CHECK_BYTE_COMBINING_FOR_INSERT(pos)                           \
   do {                                                                 \
-    if (combined_before_bytes && pos == BEGV                           \
-       || combined_after_bytes && pos == ZV)                           \
+    if ((combined_before_bytes && pos == BEGV)                         \
+       || (combined_after_bytes && pos == ZV))                         \
       byte_combining_error (); \
   } while (0)
 
@@ -1057,7 +1098,6 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
      register int nchars, nbytes;
      int inherit, prepare, before_markers;
 {
-  register Lisp_Object temp;
   int combined_before_bytes, combined_after_bytes;
 
   if (NILP (current_buffer->enable_multibyte_characters))
@@ -1220,11 +1260,9 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
      register int pos, pos_byte, nchars, nbytes;
      int inherit, before_markers;
 {
-  register Lisp_Object temp;
   struct gcpro gcpro1;
   int outgoing_nbytes = nbytes;
   int combined_before_bytes, combined_after_bytes;
-  int adjusted_nchars;
   INTERVAL intervals;
 
   /* Make OUTGOING_NBYTES describe the text
@@ -1245,7 +1283,7 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
 
   if (PT != GPT)
     move_gap_both (PT, PT_BYTE);
-  if (GAP_SIZE < nbytes)
+  if (GAP_SIZE < outgoing_nbytes)
     make_gap (outgoing_nbytes - GAP_SIZE);
   UNGCPRO;
 
@@ -1396,7 +1434,6 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
   int incoming_nbytes = to_byte - from_byte;
   int outgoing_nbytes = incoming_nbytes;
   int combined_before_bytes, combined_after_bytes;
-  int adjusted_nchars;
   INTERVAL intervals;
 
   /* Make OUTGOING_NBYTES describe the text
@@ -1628,8 +1665,8 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
       nbytes_del = STRING_BYTES (XSTRING (prev_text));
     }
 
-  if (combine_before && from == BEGV
-      || combined_after_bytes && from == ZV)
+  if ((combine_before && from == BEGV)
+      || (combined_after_bytes && from == ZV))
     {
       /* We can't combine bytes nor signal an error here.  So, let's
         pretend that the new text is just a single space.  */
@@ -1658,7 +1695,7 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
     }
 
   if (combined_before_bytes
-      || len_byte == 0 && combined_after_bytes > 0)
+      || (len_byte == 0 && combined_after_bytes > 0))
     {
       Lisp_Object deletion;
       deletion = Qnil;
@@ -1709,8 +1746,6 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
 #endif
 
   {
-    int pos = PT, pos_byte = PT_BYTE;
-
     if (from < PT)
       adjust_point (len - nchars_del, len_byte - nbytes_del);
 
@@ -1728,8 +1763,8 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
   }
 
   /* As byte combining will decrease Z, we must check this again. */
-  if (Z - GPT < end_unchanged)
-    end_unchanged = Z - GPT;
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
 
   CHECK_MARKERS ();
 
@@ -1782,7 +1817,6 @@ replace_range (from, to, new, prepare, inherit, markers)
   register Lisp_Object temp;
   struct gcpro gcpro1;
   int combined_before_bytes, combined_after_bytes;
-  int adjusted_inschars;
   INTERVAL intervals;
   int outgoing_insbytes = insbytes;
   Lisp_Object deletion;
@@ -1861,10 +1895,10 @@ replace_range (from, to, new, prepare, inherit, markers)
   if (GPT_BYTE < GPT)
     abort ();
 
-  if (GPT - BEG < beg_unchanged)
-    beg_unchanged = GPT - BEG;
-  if (Z - GPT < end_unchanged)
-    end_unchanged = Z - GPT;
+  if (GPT - BEG < BEG_UNCHANGED)
+    BEG_UNCHANGED = GPT - BEG;
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
 
   if (GAP_SIZE < insbytes)
     make_gap (insbytes - GAP_SIZE);
@@ -1886,8 +1920,8 @@ replace_range (from, to, new, prepare, inherit, markers)
   combined_after_bytes
     = count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte);
 
-  if (combined_before_bytes && from == BEGV
-      || combined_after_bytes && from == ZV)
+  if ((combined_before_bytes && from == BEGV)
+      || (combined_after_bytes && from == ZV))
     {
       /* Bytes are being combined across the region boundary.  We
          should avoid it.  We recover the original contents before
@@ -2010,8 +2044,8 @@ replace_range (from, to, new, prepare, inherit, markers)
     combine_bytes (from, from_byte, combined_before_bytes);
 
   /* As byte combining will decrease Z, we must check this again. */
-  if (Z - GPT < end_unchanged)
-    end_unchanged = Z - GPT;
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
 
   if (outgoing_insbytes == 0)
     evaporate_overlays (from);
@@ -2243,10 +2277,10 @@ del_range_2 (from, from_byte, to, to_byte)
   if (GPT_BYTE < GPT)
     abort ();
 
-  if (GPT - BEG < beg_unchanged)
-    beg_unchanged = GPT - BEG;
-  if (Z - GPT < end_unchanged)
-    end_unchanged = Z - GPT;
+  if (GPT - BEG < BEG_UNCHANGED)
+    BEG_UNCHANGED = GPT - BEG;
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
 
   if (combined_after_bytes)
     {
@@ -2259,8 +2293,8 @@ del_range_2 (from, from_byte, to, to_byte)
 
       record_insert (GPT - 1, 1);
 
-      if (Z - GPT < end_unchanged)
-       end_unchanged = Z - GPT;
+      if (Z - GPT < END_UNCHANGED)
+       END_UNCHANGED = Z - GPT;
     }
 
   CHECK_MARKERS ();
@@ -2286,14 +2320,7 @@ modify_region (buffer, start, end)
 
   prepare_to_modify_buffer (start, end, NULL);
 
-  if (start - 1 < beg_unchanged
-      || (unchanged_modified == MODIFF
-         && overlay_unchanged_modified == OVERLAY_MODIFF))
-    beg_unchanged = start - 1;
-  if (Z - end < end_unchanged
-      || (unchanged_modified == MODIFF
-         && overlay_unchanged_modified == OVERLAY_MODIFF))
-    end_unchanged = Z - end;
+  BUF_COMPUTE_UNCHANGED (buffer, start - 1, end);
 
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
@@ -2323,6 +2350,11 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
   if (!NILP (current_buffer->read_only))
     Fbarf_if_buffer_read_only ();
 
+  /* Let redisplay consider other windows than selected_window
+     if modifying another buffer.  */
+  if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+    ++windows_or_buffers_changed;
+
   /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
   if (BUF_INTERVALS (current_buffer) != 0)
     {
@@ -2621,26 +2653,26 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
   /* 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)
+       tail = XCDR (tail))
     {
       Lisp_Object elt;
       int thisbeg, thisend, thischange;
 
       /* Extract the info from the next element.  */
-      elt = XCONS (tail)->car;
+      elt = XCAR (tail);
       if (! CONSP (elt))
        continue;
-      thisbeg = XINT (XCONS (elt)->car);
+      thisbeg = XINT (XCAR (elt));
 
-      elt = XCONS (elt)->cdr;
+      elt = XCDR (elt);
       if (! CONSP (elt))
        continue;
-      thisend = XINT (XCONS (elt)->car);
+      thisend = XINT (XCAR (elt));
 
-      elt = XCONS (elt)->cdr;
+      elt = XCDR (elt);
       if (! CONSP (elt))
        continue;
-      thischange = XINT (XCONS (elt)->car);
+      thischange = XINT (XCAR (elt));
 
       /* Merge this range into the accumulated range.  */
       change += thischange;
@@ -2681,5 +2713,11 @@ syms_of_insdel ()
     "Used internally by the `combine-after-change-calls' macro.");
   Vcombine_after_change_calls = Qnil;
 
+  DEFVAR_BOOL ("inhibit-modification-hooks", &inhibit_modification_hooks,
+    "Non-nil means don't run any of the hooks that respond to buffer changes.\n\
+This affects `before-change-functions' and `after-change-functions',\n\
+as well as hooks attached to text properties and overlays.");
+  inhibit_modification_hooks = 0;
+
   defsubr (&Scombine_after_change_execute);
 }