/* 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 Free Software Foundation, Inc.
This file is part of GNU Emacs.
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)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
will add up to the right stuff in the undo list. */
record_insert (PT, nchars);
MODIFF++;
+ CHARS_MODIFF = MODIFF;
bcopy (string, GPT_ADDR, nbytes);
record_insert (PT, nchars);
MODIFF++;
+ CHARS_MODIFF = MODIFF;
GAP_SIZE -= outgoing_nbytes;
GPT += nchars;
record_insert (PT, nchars);
MODIFF++;
+ CHARS_MODIFF = MODIFF;
GAP_SIZE -= outgoing_nbytes;
GPT += nchars;
if (len == 0)
evaporate_overlays (from);
MODIFF++;
+ CHARS_MODIFF = MODIFF;
}
/* Like adjust_after_replace, but doesn't require PREV_TEXT.
if (len == 0)
evaporate_overlays (from);
MODIFF++;
+ CHARS_MODIFF = MODIFF;
}
/* Record undo information, adjust markers and position keepers for an
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;
CHECK_MARKERS ();
MODIFF++;
+ CHARS_MODIFF = MODIFF;
UNGCPRO;
signal_after_change (from, nchars_del, GPT - from);
CHECK_MARKERS ();
MODIFF++;
+ CHARS_MODIFF = MODIFF;
}
\f
/* Delete characters in current buffer
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)
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;
if (MODIFF <= SAVE_MODIFF)
record_first_change ();
MODIFF++;
+ if (! preserve_chars_modiff)
+ CHARS_MODIFF = MODIFF;
buffer->point_before_scroll = Qnil;
#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.
Lisp_Object start_marker, end_marker;
Lisp_Object preserve_marker;
struct gcpro gcpro1, gcpro2, gcpro3;
+ int count = SPECPDL_INDEX ();
if (inhibit_modification_hooks)
return;
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)
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)
free_marker (end_marker);
RESTORE_VALUE;
UNGCPRO;
+
+ unbind_to (count, Qnil);
}
/* Signal a change immediately after it happens.
signal_after_change (charpos, lendel, lenins)
int charpos, lendel, lenins;
{
+ int count = SPECPDL_INDEX ();
if (inhibit_modification_hooks)
return;
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)
if (lendel == 0)
report_interval_modification (make_number (charpos),
make_number (charpos + lenins));
+
+ unbind_to (count, Qnil);
}
Lisp_Object
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);