functions.
@end defmac
-The two variables above are temporarily bound to @code{nil} during the
-time that any of these functions is running. This means that if one of
-these functions changes the buffer, that change won't run these
-functions. If you do want a hook function to make changes that run
-these functions, make it bind these variables back to their usual
-values.
-
-One inconvenient result of this protective feature is that you cannot
-have a function in @code{after-change-functions} or
-@code{before-change-functions} which changes the value of that variable.
-But that's not a real limitation. If you want those functions to change
-the list of functions to run, simply add one fixed function to the hook,
-and code that function to look in another variable for other functions
-to call. Here is an example:
-
-@example
-(setq my-own-after-change-functions nil)
-(defun indirect-after-change-function (beg end len)
- (let ((list my-own-after-change-functions))
- (while list
- (funcall (car list) beg end len)
- (setq list (cdr list)))))
-
-@group
-(add-hooks 'after-change-functions
- 'indirect-after-change-function)
-@end group
-@end example
-
@defvar first-change-hook
This variable is a normal hook that is run whenever a buffer is changed
that was previously in the unmodified state.
described above in this section, as well as the hooks attached to
certain special text properties (@pxref{Special Properties}) and overlay
properties (@pxref{Overlay Properties}).
+
+Also, this variable is bound to non-@code{nil} while running those
+same hook variables, so that by default modifying the buffer from
+a modification hook does not cause other modification hooks to be run.
+If you do want modification hooks to be run in a particular piece of
+code that is itself run from a modification hook, then rebind locally
+@code{inhibit-modification-hooks} to @code{nil}.
@end defvar
@ignore
#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