]> code.delx.au - gnu-emacs/blobdiff - src/insdel.c
(minibuffer_completion_contents): Add return type.
[gnu-emacs] / src / insdel.c
index acc1d47395d7b1b0ce0d68f7a08f01802a429e2a..5bec29ea926c642e5c5e7bc05072577347114291 100644 (file)
@@ -1,5 +1,6 @@
 /* Buffer insertion/deletion and gap motion for GNU Emacs.
-   Copyright (C) 1985, 86,93,94,95,97,98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86,93,94,95,97,98, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -32,9 +33,6 @@ Boston, MA 02111-1307, USA.  */
 #define NULL 0
 #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 ();
 static void gap_left P_ ((int, int, int));
@@ -65,6 +63,9 @@ Lisp_Object combine_after_change_list;
 
 /* Buffer which combine_after_change_list is about.  */
 Lisp_Object combine_after_change_buffer;
+
+Lisp_Object Qinhibit_modification_hooks;
+
 \f
 /* Check all markers in the current buffer, looking for something invalid.  */
 
@@ -366,14 +367,33 @@ adjust_markers_for_delete (from, from_byte, to, to_byte)
          m->charpos -= to - from;
          m->bytepos -= to_byte - from_byte;
        }
-
       /* Here's the case where a marker is inside text being deleted.  */
       else if (charpos > from)
        {
-         record_marker_adjustment (marker, from - charpos);
+         if (! m->insertion_type)
+           /* Normal markers will end up at the beginning of the
+              re-inserted text after undoing a deletion, and must be
+              adjusted to move them to the correct place.  */ 
+           record_marker_adjustment (marker, from - charpos);
+         else if (charpos < to)
+           /* Before-insertion markers will automatically move forward
+              upon re-inserting the deleted text, so we have to arrange
+              for them to move backward to the correct position.  */
+           record_marker_adjustment (marker, charpos - to);
+
          m->charpos = from;
          m->bytepos = from_byte;
        }
+      /* Here's the case where a before-insertion marker is immediately
+        before the deleted region.  */
+      else if (charpos == from && m->insertion_type)
+       {
+         /* Undoing the change uses normal insertion, which will
+            incorrectly make MARKER move forward, so we arrange for it
+            to then move backward to the correct place at the beginning
+            of the deleted region.  */
+         record_marker_adjustment (marker, to - from);
+       }
 
       marker = m->chain;
     }
@@ -500,10 +520,9 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
 /* Make the gap NBYTES_ADDED bytes longer.  */
 
 void
-make_gap (nbytes_added)
+make_gap_larger (nbytes_added)
      int nbytes_added;
 {
-  unsigned char *result;
   Lisp_Object tem;
   int real_gap_loc;
   int real_gap_loc_byte;
@@ -514,10 +533,13 @@ make_gap (nbytes_added)
 
   /* Don't allow a buffer size that won't fit in an int
      even if it will fit in a Lisp integer.
-     That won't work because so many places use `int'.  */
+     That won't work because so many places use `int'.
+
+     Make sure we don't introduce overflows in the calculation.  */
      
-  if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added
-      >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
+  if (Z_BYTE - BEG_BYTE + GAP_SIZE
+      >= (((EMACS_INT) 1 << (min (VALBITS, BITS_PER_INT) - 1)) - 1
+         - nbytes_added))
     error ("Buffer exceeds maximum size");
 
   enlarge_buffer_text (current_buffer, nbytes_added);
@@ -549,6 +571,78 @@ make_gap (nbytes_added)
 
   Vinhibit_quit = tem;
 }
+
+
+/* Make the gap NBYTES_REMOVED bytes shorted.  */
+
+void
+make_gap_smaller (nbytes_removed)
+     int nbytes_removed;
+{
+  Lisp_Object tem;
+  int real_gap_loc;
+  int real_gap_loc_byte;
+  int real_Z;
+  int real_Z_byte;
+  int real_beg_unchanged;
+  int new_gap_size;
+
+  /* Make sure the gap is at least 20 bytes.  */
+  if (GAP_SIZE - nbytes_removed < 20)
+    nbytes_removed = GAP_SIZE - 20;
+
+  /* Prevent quitting in move_gap.  */
+  tem = Vinhibit_quit;
+  Vinhibit_quit = Qt;
+
+  real_gap_loc = GPT;
+  real_gap_loc_byte = GPT_BYTE;
+  new_gap_size = GAP_SIZE - nbytes_removed;
+  real_Z = Z;
+  real_Z_byte = Z_BYTE;
+  real_beg_unchanged = BEG_UNCHANGED;
+
+  /* Pretend that the last unwanted part of the gap is the entire gap,
+     and that the first desired part of the gap is part of the buffer
+     text.  */
+  bzero (GPT_ADDR, new_gap_size);
+  GPT += new_gap_size;
+  GPT_BYTE += new_gap_size;
+  Z += new_gap_size;
+  Z_BYTE += new_gap_size;
+  GAP_SIZE = nbytes_removed;
+
+  /* Move the unwanted pretend gap to the end of the buffer.  This
+     adjusts the markers properly too.  */
+  gap_right (Z, Z_BYTE);
+
+  enlarge_buffer_text (current_buffer, -nbytes_removed);
+
+  /* Now restore the desired gap.  */
+  GAP_SIZE = new_gap_size;
+  GPT = real_gap_loc;
+  GPT_BYTE = real_gap_loc_byte;
+  Z = real_Z;
+  Z_BYTE = real_Z_byte;
+  BEG_UNCHANGED = real_beg_unchanged;
+
+  /* Put an anchor.  */
+  *(Z_ADDR) = 0;
+
+  Vinhibit_quit = tem;
+}
+
+void
+make_gap (nbytes_added)
+     int nbytes_added;
+{
+  if (nbytes_added >= 0)
+    make_gap_larger (nbytes_added);
+#if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
+  else
+    make_gap_smaller (-nbytes_added);
+#endif
+}
 \f
 /* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
    FROM_MULTIBYTE says whether the incoming text is multibyte.
@@ -894,6 +988,9 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
      register int nchars, nbytes;
      int inherit, prepare, before_markers;
 {
+  if (nchars == 0)
+    return;
+  
   if (NILP (current_buffer->enable_multibyte_characters))
     nchars = nbytes;
 
@@ -934,6 +1031,10 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
   if (GPT_BYTE < GPT)
     abort ();
 
+  /* The insert may have been in the unchanged region, so check again. */
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
+
   adjust_overlays_for_insert (PT, nchars);
   adjust_markers_for_insert (PT, PT_BYTE,
                             PT + nchars, PT_BYTE + nbytes,
@@ -1057,6 +1158,10 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
   if (GPT_BYTE < GPT)
     abort ();
 
+  /* The insert may have been in the unchanged region, so check again. */
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
+
   adjust_overlays_for_insert (PT, nchars);
   adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
                             PT_BYTE + outgoing_nbytes,
@@ -1204,6 +1309,10 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
   if (GPT_BYTE < GPT)
     abort ();
 
+  /* The insert may have been in the unchanged region, so check again. */
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
+
   adjust_overlays_for_insert (PT, nchars);
   adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
                             PT_BYTE + outgoing_nbytes,
@@ -1297,6 +1406,56 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
   MODIFF++;
 }
 
+/* Like adjust_after_replace, but doesn't require PREV_TEXT.
+   This is for use when undo is not enabled in the current buffer.  */
+
+void
+adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del, len, len_byte)
+     int from, from_byte, nchars_del, nbytes_del, len, len_byte;
+{
+#ifdef BYTE_COMBINING_DEBUG
+  if (count_combining_before (GPT_ADDR, len_byte, from, from_byte)
+      || count_combining_after (GPT_ADDR, len_byte, from, from_byte))
+    abort ();
+#endif
+
+  /* Update various buffer positions for the new text.  */
+  GAP_SIZE -= len_byte;
+  ZV += len; Z+= len;
+  ZV_BYTE += len_byte; Z_BYTE += len_byte;
+  GPT += len; GPT_BYTE += len_byte;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+  if (nchars_del > 0)
+    adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+                               len, len_byte);
+  else
+    adjust_markers_for_insert (from, from_byte,
+                              from + len, from_byte + len_byte, 0);
+
+  if (len > nchars_del)
+    adjust_overlays_for_insert (from, len - nchars_del);
+  else if (len < nchars_del)
+    adjust_overlays_for_delete (from, nchars_del - len);
+  if (BUF_INTERVALS (current_buffer) != 0)
+    {
+      offset_intervals (current_buffer, from, len - nchars_del);
+    }
+
+  if (from < PT)
+    adjust_point (len - nchars_del, len_byte - nbytes_del);
+
+  /* As byte combining will decrease Z, we must check this again. */
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
+
+  CHECK_MARKERS ();
+
+  if (len == 0)
+    evaporate_overlays (from);
+  MODIFF++;
+}
+
 /* Record undo information, adjust markers and position keepers for an
    insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE).  The
    text already exists in the current buffer but character length (TO
@@ -1347,6 +1506,7 @@ replace_range (from, to, new, prepare, inherit, markers)
   CHECK_MARKERS ();
 
   GCPRO1 (new);
+  deletion = Qnil;
 
   if (prepare)
     {
@@ -1400,13 +1560,6 @@ replace_range (from, to, new, prepare, inherit, markers)
   if (! EQ (current_buffer->undo_list, Qt))
     deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
 
-  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;
   Z -= nchars_del;
@@ -1466,10 +1619,11 @@ replace_range (from, to, new, prepare, inherit, markers)
      adjusting the markers that bound the overlays.  */
   adjust_overlays_for_delete (from, nchars_del);
   adjust_overlays_for_insert (from, inschars);
+
+  /* Adjust markers for the deletion and the insertion.  */
   if (markers)
-    adjust_markers_for_insert (from, from_byte,
-                              from + inschars, from_byte + outgoing_insbytes,
-                              0);
+    adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+                               inschars, outgoing_insbytes);
 
   offset_intervals (current_buffer, from, inschars - nchars_del);
 
@@ -1533,7 +1687,7 @@ del_range_1 (from, to, prepare, ret_string)
     {
       int range_length = to - from;
       prepare_to_modify_buffer (from, to, &from);
-      to = from + range_length;
+      to = min (ZV, from + range_length);
     }
 
   from_byte = CHAR_TO_BYTE (from);
@@ -1576,7 +1730,12 @@ del_range_byte (from_byte, to_byte, prepare)
 
       if (old_from != from)
        from_byte = CHAR_TO_BYTE (from);
-      if (old_to == Z - to)
+      if (to > ZV)
+       {
+         to = ZV;
+         to_byte = ZV_BYTE;
+       }
+      else if (old_to == Z - to)
        to_byte = CHAR_TO_BYTE (to);
     }
 
@@ -1615,7 +1774,12 @@ del_range_both (from, from_byte, to, to_byte, prepare)
 
       if (old_from != from)
        from_byte = CHAR_TO_BYTE (from);
-      if (old_to == Z - to)
+      if (to > ZV)
+       {
+         to = ZV;
+         to_byte = ZV_BYTE;
+       }
+      else if (old_to == Z - to)
        to_byte = CHAR_TO_BYTE (to);
     }
 
@@ -1872,6 +2036,8 @@ signal_before_change (start_int, end_int, preserve_ptr)
       Lisp_Object before_change_functions;
       Lisp_Object after_change_functions;
       struct gcpro gcpro1, gcpro2;
+      struct buffer *old = current_buffer;
+      struct buffer *new;
 
       PRESERVE_VALUE;
       PRESERVE_START_END;
@@ -1891,9 +2057,21 @@ signal_before_change (start_int, end_int, preserve_ptr)
       args[2] = FETCH_END;
       run_hook_list_with_args (before_change_functions, 3, args);
 
-      /* "Unbind" the variables we "bound" to nil.  */
-      Vbefore_change_functions = before_change_functions;
-      Vafter_change_functions = after_change_functions;
+      /* "Unbind" the variables we "bound" to nil.  Beware a
+        buffer-local hook which changes the buffer when run (e.g. W3).  */
+      if (old != current_buffer)
+       {
+         new = current_buffer;
+         set_buffer_internal (old);
+         Vbefore_change_functions = before_change_functions;
+         Vafter_change_functions = after_change_functions;
+         set_buffer_internal (new);
+       }
+      else
+       {
+         Vbefore_change_functions = before_change_functions;
+         Vafter_change_functions = after_change_functions;
+       }
       UNGCPRO;
     }
 
@@ -1959,6 +2137,8 @@ signal_after_change (charpos, lendel, lenins)
       Lisp_Object args[4];
       Lisp_Object before_change_functions;
       Lisp_Object after_change_functions;
+      struct buffer *old = current_buffer;
+      struct buffer *new;
       struct gcpro gcpro1, gcpro2;
 
       /* "Bind" before-change-functions and after-change-functions
@@ -1978,9 +2158,21 @@ signal_after_change (charpos, lendel, lenins)
       run_hook_list_with_args (after_change_functions,
                               4, args);
 
-      /* "Unbind" the variables we "bound" to nil.  */
-      Vbefore_change_functions = before_change_functions;
-      Vafter_change_functions = after_change_functions;
+      /* "Unbind" the variables we "bound" to nil.  Beware a
+        buffer-local hook which changes the buffer when run (e.g. W3).  */
+      if (old != current_buffer)
+       {
+         new = current_buffer;
+         set_buffer_internal (old);
+         Vbefore_change_functions = before_change_functions;
+         Vafter_change_functions = after_change_functions;
+         set_buffer_internal (new);
+       }
+      else
+       {
+         Vbefore_change_functions = before_change_functions;
+         Vafter_change_functions = after_change_functions;
+       }
       UNGCPRO;
     }
 
@@ -2009,9 +2201,9 @@ Fcombine_after_change_execute_1 (val)
 }
 
 DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
-  Scombine_after_change_execute, 0, 0, 0,
-  "This function is for use internally in `combine-after-change-calls'.")
-  ()
+       Scombine_after_change_execute, 0, 0, 0,
+       doc: /* This function is for use internally in `combine-after-change-calls'.  */)
+     ()
 {
   int count = specpdl_ptr - specpdl;
   int beg, end, change;
@@ -2090,17 +2282,19 @@ syms_of_insdel ()
   combine_after_change_buffer = Qnil;
 
   DEFVAR_BOOL ("check-markers-debug-flag", &check_markers_debug_flag,
-    "Non-nil means enable debugging checks for invalid marker positions.");
+              doc: /* Non-nil means enable debugging checks for invalid marker positions.  */);
   check_markers_debug_flag = 0;
   DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls,
-    "Used internally by the `combine-after-change-calls' macro.");
+              doc: /* 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.");
+              doc: /* Non-nil means don't run any of the hooks that respond to buffer changes.
+This affects `before-change-functions' and `after-change-functions',
+as well as hooks attached to text properties and overlays.  */);
   inhibit_modification_hooks = 0;
+  Qinhibit_modification_hooks = intern ("inhibit-modification-hooks");
+  staticpro (&Qinhibit_modification_hooks);
 
   defsubr (&Scombine_after_change_execute);
 }