(run-python): Remove '' from sys.path.
[bpt/emacs.git] / src / insdel.c
index b97539c..a41f03b 100644 (file)
@@ -1,13 +1,14 @@
 /* Buffer insertion/deletion and gap motion for GNU Emacs.
    Copyright (C) 1985, 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+                 2002, 2003, 2004, 2005, 2006, 2007, 2008
+                 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,16 +16,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include <config.h>
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "window.h"
 #include "blockinput.h"
 #include "region-cache.h"
@@ -415,13 +414,8 @@ adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers)
 
   for (m = BUF_MARKERS (current_buffer); m; m = m->next)
     {
-      /* In a single-byte buffer, a marker's two positions must be
-        equal.  */
-      if (Z == Z_BYTE)
-       {
-         if (m->charpos != m->bytepos)
-           abort ();
-       }
+      eassert (m->bytepos >= m->charpos
+              && m->bytepos - m->charpos <= Z_BYTE - Z);
 
       if (m->bytepos == from_byte)
        {
@@ -468,9 +462,7 @@ adjust_point (nchars, nbytes)
   BUF_PT_BYTE (current_buffer) += nbytes;
 
   /* In a single-byte buffer, the two positions must be equal.  */
-  if (ZV == ZV_BYTE
-      && PT != PT_BYTE)
-    abort ();
+  eassert (PT_BYTE >= PT && PT_BYTE - PT <= ZV_BYTE - ZV);
 }
 \f
 /* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
@@ -659,22 +651,11 @@ copy_text (from_addr, to_addr, nbytes,
       int bytes_left = nbytes;
       Lisp_Object tbl = Qnil;
 
-      /* We set the variable tbl to the reverse table of
-         Vnonascii_translation_table in advance.  */
-      if (CHAR_TABLE_P (Vnonascii_translation_table))
-       {
-         tbl = Fchar_table_extra_slot (Vnonascii_translation_table,
-                                       make_number (0));
-         if (!CHAR_TABLE_P (tbl))
-           tbl = Qnil;
-       }
-
-      /* Convert multibyte to single byte.  */
       while (bytes_left > 0)
        {
          int thislen, c;
          c = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
-         if (!SINGLE_BYTE_CHAR_P (c))
+         if (!ASCII_CHAR_P (c))
            c = multibyte_char_to_unibyte (c, tbl);
          *to_addr++ = c;
          from_addr += thislen;
@@ -1007,6 +988,7 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
      will add up to the right stuff in the undo list.  */
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   bcopy (string, GPT_ADDR, nbytes);
 
@@ -1144,6 +1126,7 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
 
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
   GPT += nchars;
@@ -1178,6 +1161,50 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
                               current_buffer, inherit);
 
   adjust_point (nchars, outgoing_nbytes);
+
+  CHECK_MARKERS ();
+}
+\f
+/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
+   starting at GPT_ADDR.  */
+
+void
+insert_from_gap (nchars, nbytes)
+     register EMACS_INT nchars, nbytes;
+{
+  if (NILP (current_buffer->enable_multibyte_characters))
+    nchars = nbytes;
+
+  record_insert (GPT, nchars);
+  MODIFF++;
+
+  GAP_SIZE -= nbytes;
+  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.  */
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  adjust_overlays_for_insert (GPT - nchars, nchars);
+  adjust_markers_for_insert (GPT - nchars, GPT_BYTE - nbytes,
+                            GPT, GPT_BYTE, 0);
+
+  if (BUF_INTERVALS (current_buffer) != 0)
+    {
+      offset_intervals (current_buffer, GPT - nchars, nchars);
+      graft_intervals_into_buffer (NULL_INTERVAL, GPT - nchars, nchars,
+                                  current_buffer, 0);
+    }
+
+  if (GPT - nchars < PT)
+    adjust_point (nchars, nbytes);
+
+  CHECK_MARKERS ();
 }
 \f
 /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
@@ -1295,6 +1322,7 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
 
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
   GPT += nchars;
@@ -1322,7 +1350,7 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
 
   /* Get the intervals for the part of the string we are inserting.  */
   intervals = BUF_INTERVALS (buf);
-  if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
+  if (nchars < BUF_Z (buf) - BUF_BEG (buf))
     {
       if (buf == current_buffer && PT <= from)
        from += nchars;
@@ -1403,6 +1431,7 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
   if (len == 0)
     evaporate_overlays (from);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 }
 
 /* Like adjust_after_replace, but doesn't require PREV_TEXT.
@@ -1453,6 +1482,7 @@ adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del, len, len_b
   if (len == 0)
     evaporate_overlays (from);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 }
 
 /* Record undo information, adjust markers and position keepers for an
@@ -1598,8 +1628,12 @@ replace_range (from, to, new, prepare, inherit, markers)
 
   if (! EQ (current_buffer->undo_list, Qt))
     {
+      /* Record the insertion first, so that when we undo,
+        the deletion will be undone first.  Thus, undo
+        will insert before deleting, and thus will keep
+        the markers before and after this text separate.  */
+      record_insert (from + SCHARS (deletion), inschars);
       record_delete (from, deletion);
-      record_insert (from, inschars);
     }
 
   GAP_SIZE -= outgoing_insbytes;
@@ -1645,6 +1679,7 @@ replace_range (from, to, new, prepare, inherit, markers)
   CHECK_MARKERS ();
 
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
   UNGCPRO;
 
   signal_after_change (from, nchars_del, GPT - from);
@@ -1769,6 +1804,7 @@ replace_range_2 (from, from_byte, to, to_byte, ins, inschars, insbytes, markers)
   CHECK_MARKERS ();
 
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 }
 \f
 /* Delete characters in current buffer
@@ -1950,6 +1986,7 @@ del_range_2 (from, from_byte, to, to_byte, ret_string)
   if (! EQ (current_buffer->undo_list, Qt))
     record_delete (from, deletion);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   /* Relocate point as if it were a marker.  */
   if (from < PT)
@@ -1990,12 +2027,15 @@ del_range_2 (from, from_byte, to, to_byte, ret_string)
    character positions START to END.  This checks the read-only
    properties of the region, calls the necessary modification hooks,
    and warns the next redisplay that it should pay attention to that
-   area.  */
+   area.
+
+   If PRESERVE_CHARS_MODIFF is non-zero, do not update CHARS_MODIFF.
+   Otherwise set CHARS_MODIFF to the new value of MODIFF.  */
 
 void
-modify_region (buffer, start, end)
+modify_region (buffer, start, end, preserve_chars_modiff)
      struct buffer *buffer;
-     int start, end;
+     int start, end, preserve_chars_modiff;
 {
   struct buffer *old_buffer = current_buffer;
 
@@ -2009,6 +2049,8 @@ modify_region (buffer, start, end)
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
   MODIFF++;
+  if (! preserve_chars_modiff)
+    CHARS_MODIFF = MODIFF;
 
   buffer->point_before_scroll = Qnil;
 
@@ -2120,6 +2162,21 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
 #define FETCH_END                              \
   (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
 
+/* Set a variable to nil if an error occurred.
+   Don't change the variable if there was no error.
+   VAL is a cons-cell (VARIABLE . NO-ERROR-FLAG).
+   VARIABLE is the variable to maybe set to nil.
+   NO-ERROR-FLAG is nil if there was an error,
+   anything else meaning no error (so this function does nothing).  */
+Lisp_Object
+reset_var_on_error (val)
+     Lisp_Object val;
+{
+  if (NILP (XCDR (val)))
+    Fset (XCAR (val), Qnil);
+  return Qnil;
+}
+
 /* Signal a change to the buffer immediately before it happens.
    START_INT and END_INT are the bounds of the text to be changed.
 
@@ -2135,6 +2192,7 @@ signal_before_change (start_int, end_int, preserve_ptr)
   Lisp_Object start_marker, end_marker;
   Lisp_Object preserve_marker;
   struct gcpro gcpro1, gcpro2, gcpro3;
+  int count = SPECPDL_INDEX ();
 
   if (inhibit_modification_hooks)
     return;
@@ -2146,6 +2204,8 @@ signal_before_change (start_int, end_int, preserve_ptr)
   end_marker = Qnil;
   GCPRO3 (preserve_marker, start_marker, end_marker);
 
+  specbind (Qinhibit_modification_hooks, Qt);
+
   /* If buffer is unmodified, run a special hook for that case.  */
   if (SAVE_MODIFF >= MODIFF
       && !NILP (Vfirst_change_hook)
@@ -2160,46 +2220,22 @@ signal_before_change (start_int, end_int, preserve_ptr)
   if (!NILP (Vbefore_change_functions))
     {
       Lisp_Object args[3];
-      Lisp_Object before_change_functions;
-      Lisp_Object after_change_functions;
-      struct gcpro gcpro1, gcpro2;
-      struct buffer *old = current_buffer;
-      struct buffer *new;
+      Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil);
 
       PRESERVE_VALUE;
       PRESERVE_START_END;
 
-      /* "Bind" before-change-functions and after-change-functions
-        to nil--but in a way that errors don't know about.
-        That way, if there's an error in them, they will stay nil.  */
-      before_change_functions = Vbefore_change_functions;
-      after_change_functions = Vafter_change_functions;
-      Vbefore_change_functions = Qnil;
-      Vafter_change_functions = Qnil;
-      GCPRO2 (before_change_functions, after_change_functions);
+      /* Mark before-change-functions to be reset to nil in case of error.  */
+      record_unwind_protect (reset_var_on_error, rvoe_arg);
 
       /* Actually run the hook functions.  */
       args[0] = Qbefore_change_functions;
       args[1] = FETCH_START;
       args[2] = FETCH_END;
-      run_hook_list_with_args (before_change_functions, 3, args);
+      Frun_hook_with_args (3, args);
 
-      /* "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;
+      /* There was no error: unarm the reset_on_error.  */
+      XSETCDR (rvoe_arg, Qt);
     }
 
   if (current_buffer->overlays_before || current_buffer->overlays_after)
@@ -2215,6 +2251,8 @@ signal_before_change (start_int, end_int, preserve_ptr)
     free_marker (end_marker);
   RESTORE_VALUE;
   UNGCPRO;
+
+  unbind_to (count, Qnil);
 }
 
 /* Signal a change immediately after it happens.
@@ -2228,6 +2266,7 @@ void
 signal_after_change (charpos, lendel, lenins)
      int charpos, lendel, lenins;
 {
+  int count = SPECPDL_INDEX ();
   if (inhibit_modification_hooks)
     return;
 
@@ -2258,48 +2297,25 @@ signal_after_change (charpos, lendel, lenins)
   if (!NILP (combine_after_change_list))
     Fcombine_after_change_execute ();
 
+  specbind (Qinhibit_modification_hooks, Qt);
+
   if (!NILP (Vafter_change_functions))
     {
       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
-        to nil--but in a way that errors don't know about.
-        That way, if there's an error in them, they will stay nil.  */
-      before_change_functions = Vbefore_change_functions;
-      after_change_functions = Vafter_change_functions;
-      Vbefore_change_functions = Qnil;
-      Vafter_change_functions = Qnil;
-      GCPRO2 (before_change_functions, after_change_functions);
+      Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil);
+
+      /* Mark after-change-functions to be reset to nil in case of error.  */
+      record_unwind_protect (reset_var_on_error, rvoe_arg);
 
       /* Actually run the hook functions.  */
       args[0] = Qafter_change_functions;
       XSETFASTINT (args[1], charpos);
       XSETFASTINT (args[2], charpos + lenins);
       XSETFASTINT (args[3], lendel);
-      run_hook_list_with_args (after_change_functions,
-                              4, args);
+      Frun_hook_with_args (4, args);
 
-      /* "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;
+      /* There was no error: unarm the reset_on_error.  */
+      XSETCDR (rvoe_arg, Qt);
     }
 
   if (current_buffer->overlays_before || current_buffer->overlays_after)
@@ -2315,6 +2331,8 @@ signal_after_change (charpos, lendel, lenins)
   if (lendel == 0)
     report_interval_modification (make_number (charpos),
                                  make_number (charpos + lenins));
+
+  unbind_to (count, Qnil);
 }
 
 Lisp_Object
@@ -2338,6 +2356,17 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
   if (NILP (combine_after_change_list))
     return Qnil;
 
+  /* It is rare for combine_after_change_buffer to be invalid, but
+     possible.  It can happen when combine-after-change-calls is
+     non-nil, and insertion calls a file handler (e.g. through
+     lock_file) which scribbles into a temp file -- cyd  */
+  if (!BUFFERP (combine_after_change_buffer)
+      || NILP (XBUFFER (combine_after_change_buffer)->name))
+    {
+      combine_after_change_list = Qnil;
+      return Qnil;
+    }
+
   record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
 
   Fset_buffer (combine_after_change_buffer);