aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2007-08-21 18:22:03 +0000
committerStefan Monnier2007-08-21 18:22:03 +0000
commit97c4ef2a204f2be3db8de5c900046abe09d0582a (patch)
treed70157d7cbda014f388718d4992374bc0341e913
parentd5dac3b9bd5baa34ebb0506d0cd4460397a03d81 (diff)
downloademacs-97c4ef2a204f2be3db8de5c900046abe09d0582a.tar.gz
emacs-97c4ef2a204f2be3db8de5c900046abe09d0582a.zip
(reset_var_on_error): New fun.
(signal_before_change, signal_after_change): Use it to reset (after|before)-change-functions to nil in case of error. Bind inhibit-modification-hooks to t. Don't bind (after|before)-change-functions to nil while they run.
-rw-r--r--etc/NEWS5
-rw-r--r--lispref/text.texi36
-rw-r--r--src/ChangeLog8
-rw-r--r--src/insdel.c100
4 files changed, 58 insertions, 91 deletions
diff --git a/etc/NEWS b/etc/NEWS
index c652703bcf1..32b555f14c9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -79,6 +79,11 @@ in to make it use the scrollbars from the system theme.
79 79
80* Lisp Changes in Emacs 22.2. 80* Lisp Changes in Emacs 22.2.
81 81
82+++
83** inhibit-modification-hooks is bound to t while running modification hooks.
84As a happy consequence, after-change-functions and before-change-functions
85are not bound to nil any more while running an (after|before)-change-function.
86
82** New function `window-full-width-p' returns t if a window is as wide 87** New function `window-full-width-p' returns t if a window is as wide
83as its frame. 88as its frame.
84 89
diff --git a/lispref/text.texi b/lispref/text.texi
index 4448e1cc402..bad68b7f8ae 100644
--- a/lispref/text.texi
+++ b/lispref/text.texi
@@ -4364,35 +4364,6 @@ because it may lead to inefficient behavior for some change hook
4364functions. 4364functions.
4365@end defmac 4365@end defmac
4366 4366
4367The two variables above are temporarily bound to @code{nil} during the
4368time that any of these functions is running. This means that if one of
4369these functions changes the buffer, that change won't run these
4370functions. If you do want a hook function to make changes that run
4371these functions, make it bind these variables back to their usual
4372values.
4373
4374One inconvenient result of this protective feature is that you cannot
4375have a function in @code{after-change-functions} or
4376@code{before-change-functions} which changes the value of that variable.
4377But that's not a real limitation. If you want those functions to change
4378the list of functions to run, simply add one fixed function to the hook,
4379and code that function to look in another variable for other functions
4380to call. Here is an example:
4381
4382@example
4383(setq my-own-after-change-functions nil)
4384(defun indirect-after-change-function (beg end len)
4385 (let ((list my-own-after-change-functions))
4386 (while list
4387 (funcall (car list) beg end len)
4388 (setq list (cdr list)))))
4389
4390@group
4391(add-hooks 'after-change-functions
4392 'indirect-after-change-function)
4393@end group
4394@end example
4395
4396@defvar first-change-hook 4367@defvar first-change-hook
4397This variable is a normal hook that is run whenever a buffer is changed 4368This variable is a normal hook that is run whenever a buffer is changed
4398that was previously in the unmodified state. 4369that was previously in the unmodified state.
@@ -4404,6 +4375,13 @@ disabled; none of them run. This affects all the hook variables
4404described above in this section, as well as the hooks attached to 4375described above in this section, as well as the hooks attached to
4405certain special text properties (@pxref{Special Properties}) and overlay 4376certain special text properties (@pxref{Special Properties}) and overlay
4406properties (@pxref{Overlay Properties}). 4377properties (@pxref{Overlay Properties}).
4378
4379Also, this variable is bound to non-@code{nil} while running those
4380same hook variables, so that by default modifying the buffer from
4381a modification hook does not cause other modification hooks to be run.
4382If you do want modification hooks to be run in a particular piece of
4383code that is itself run from a modification hook, then rebind locally
4384@code{inhibit-modification-hooks} to @code{nil}.
4407@end defvar 4385@end defvar
4408 4386
4409@ignore 4387@ignore
diff --git a/src/ChangeLog b/src/ChangeLog
index add0663a648..bf015d6959f 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
12007-08-21 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * insdel.c (reset_var_on_error): New fun.
4 (signal_before_change, signal_after_change):
5 Use it to reset (after|before)-change-functions to nil in case of error.
6 Bind inhibit-modification-hooks to t.
7 Don't bind (after|before)-change-functions to nil while they run.
8
12007-08-19 Andreas Schwab <schwab@suse.de> 92007-08-19 Andreas Schwab <schwab@suse.de>
2 10
3 * alloc.c (pure): Round PURESIZE up. 11 * alloc.c (pure): Round PURESIZE up.
diff --git a/src/insdel.c b/src/insdel.c
index 14e7478e69a..cd8e2738f9a 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -2137,6 +2137,21 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
2137#define FETCH_END \ 2137#define FETCH_END \
2138 (! NILP (end_marker) ? Fmarker_position (end_marker) : end) 2138 (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
2139 2139
2140/* Set a variable to nil if an error occurred.
2141 Don't change the variable if there was no error.
2142 VAL is a cons-cell (VARIABLE . NO-ERROR-FLAG).
2143 VARIABLE is the variable to maybe set to nil.
2144 NO-ERROR-FLAG is nil if there was an error,
2145 anything else meaning no error (so this function does nothing). */
2146Lisp_Object
2147reset_var_on_error (val)
2148 Lisp_Object val;
2149{
2150 if (NILP (XCDR (val)))
2151 Fset (XCAR (val), Qnil);
2152 return Qnil;
2153}
2154
2140/* Signal a change to the buffer immediately before it happens. 2155/* Signal a change to the buffer immediately before it happens.
2141 START_INT and END_INT are the bounds of the text to be changed. 2156 START_INT and END_INT are the bounds of the text to be changed.
2142 2157
@@ -2152,6 +2167,7 @@ signal_before_change (start_int, end_int, preserve_ptr)
2152 Lisp_Object start_marker, end_marker; 2167 Lisp_Object start_marker, end_marker;
2153 Lisp_Object preserve_marker; 2168 Lisp_Object preserve_marker;
2154 struct gcpro gcpro1, gcpro2, gcpro3; 2169 struct gcpro gcpro1, gcpro2, gcpro3;
2170 int count = SPECPDL_INDEX ();
2155 2171
2156 if (inhibit_modification_hooks) 2172 if (inhibit_modification_hooks)
2157 return; 2173 return;
@@ -2163,6 +2179,8 @@ signal_before_change (start_int, end_int, preserve_ptr)
2163 end_marker = Qnil; 2179 end_marker = Qnil;
2164 GCPRO3 (preserve_marker, start_marker, end_marker); 2180 GCPRO3 (preserve_marker, start_marker, end_marker);
2165 2181
2182 specbind (Qinhibit_modification_hooks, Qt);
2183
2166 /* If buffer is unmodified, run a special hook for that case. */ 2184 /* If buffer is unmodified, run a special hook for that case. */
2167 if (SAVE_MODIFF >= MODIFF 2185 if (SAVE_MODIFF >= MODIFF
2168 && !NILP (Vfirst_change_hook) 2186 && !NILP (Vfirst_change_hook)
@@ -2177,46 +2195,22 @@ signal_before_change (start_int, end_int, preserve_ptr)
2177 if (!NILP (Vbefore_change_functions)) 2195 if (!NILP (Vbefore_change_functions))
2178 { 2196 {
2179 Lisp_Object args[3]; 2197 Lisp_Object args[3];
2180 Lisp_Object before_change_functions; 2198 Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil);
2181 Lisp_Object after_change_functions;
2182 struct gcpro gcpro1, gcpro2;
2183 struct buffer *old = current_buffer;
2184 struct buffer *new;
2185 2199
2186 PRESERVE_VALUE; 2200 PRESERVE_VALUE;
2187 PRESERVE_START_END; 2201 PRESERVE_START_END;
2188 2202
2189 /* "Bind" before-change-functions and after-change-functions 2203 /* Mark before-change-functions to be reset to nil in case of error. */
2190 to nil--but in a way that errors don't know about. 2204 record_unwind_protect (reset_var_on_error, rvoe_arg);
2191 That way, if there's an error in them, they will stay nil. */
2192 before_change_functions = Vbefore_change_functions;
2193 after_change_functions = Vafter_change_functions;
2194 Vbefore_change_functions = Qnil;
2195 Vafter_change_functions = Qnil;
2196 GCPRO2 (before_change_functions, after_change_functions);
2197 2205
2198 /* Actually run the hook functions. */ 2206 /* Actually run the hook functions. */
2199 args[0] = Qbefore_change_functions; 2207 args[0] = Qbefore_change_functions;
2200 args[1] = FETCH_START; 2208 args[1] = FETCH_START;
2201 args[2] = FETCH_END; 2209 args[2] = FETCH_END;
2202 run_hook_list_with_args (before_change_functions, 3, args); 2210 Frun_hook_with_args (3, args);
2203 2211
2204 /* "Unbind" the variables we "bound" to nil. Beware a 2212 /* There was no error: unarm the reset_on_error. */
2205 buffer-local hook which changes the buffer when run (e.g. W3). */ 2213 XSETCDR (rvoe_arg, Qt);
2206 if (old != current_buffer)
2207 {
2208 new = current_buffer;
2209 set_buffer_internal (old);
2210 Vbefore_change_functions = before_change_functions;
2211 Vafter_change_functions = after_change_functions;
2212 set_buffer_internal (new);
2213 }
2214 else
2215 {
2216 Vbefore_change_functions = before_change_functions;
2217 Vafter_change_functions = after_change_functions;
2218 }
2219 UNGCPRO;
2220 } 2214 }
2221 2215
2222 if (current_buffer->overlays_before || current_buffer->overlays_after) 2216 if (current_buffer->overlays_before || current_buffer->overlays_after)
@@ -2232,6 +2226,8 @@ signal_before_change (start_int, end_int, preserve_ptr)
2232 free_marker (end_marker); 2226 free_marker (end_marker);
2233 RESTORE_VALUE; 2227 RESTORE_VALUE;
2234 UNGCPRO; 2228 UNGCPRO;
2229
2230 unbind_to (count, Qnil);
2235} 2231}
2236 2232
2237/* Signal a change immediately after it happens. 2233/* Signal a change immediately after it happens.
@@ -2245,6 +2241,7 @@ void
2245signal_after_change (charpos, lendel, lenins) 2241signal_after_change (charpos, lendel, lenins)
2246 int charpos, lendel, lenins; 2242 int charpos, lendel, lenins;
2247{ 2243{
2244 int count = SPECPDL_INDEX ();
2248 if (inhibit_modification_hooks) 2245 if (inhibit_modification_hooks)
2249 return; 2246 return;
2250 2247
@@ -2275,48 +2272,25 @@ signal_after_change (charpos, lendel, lenins)
2275 if (!NILP (combine_after_change_list)) 2272 if (!NILP (combine_after_change_list))
2276 Fcombine_after_change_execute (); 2273 Fcombine_after_change_execute ();
2277 2274
2275 specbind (Qinhibit_modification_hooks, Qt);
2276
2278 if (!NILP (Vafter_change_functions)) 2277 if (!NILP (Vafter_change_functions))
2279 { 2278 {
2280 Lisp_Object args[4]; 2279 Lisp_Object args[4];
2281 Lisp_Object before_change_functions; 2280 Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil);
2282 Lisp_Object after_change_functions; 2281
2283 struct buffer *old = current_buffer; 2282 /* Mark after-change-functions to be reset to nil in case of error. */
2284 struct buffer *new; 2283 record_unwind_protect (reset_var_on_error, rvoe_arg);
2285 struct gcpro gcpro1, gcpro2;
2286
2287 /* "Bind" before-change-functions and after-change-functions
2288 to nil--but in a way that errors don't know about.
2289 That way, if there's an error in them, they will stay nil. */
2290 before_change_functions = Vbefore_change_functions;
2291 after_change_functions = Vafter_change_functions;
2292 Vbefore_change_functions = Qnil;
2293 Vafter_change_functions = Qnil;
2294 GCPRO2 (before_change_functions, after_change_functions);
2295 2284
2296 /* Actually run the hook functions. */ 2285 /* Actually run the hook functions. */
2297 args[0] = Qafter_change_functions; 2286 args[0] = Qafter_change_functions;
2298 XSETFASTINT (args[1], charpos); 2287 XSETFASTINT (args[1], charpos);
2299 XSETFASTINT (args[2], charpos + lenins); 2288 XSETFASTINT (args[2], charpos + lenins);
2300 XSETFASTINT (args[3], lendel); 2289 XSETFASTINT (args[3], lendel);
2301 run_hook_list_with_args (after_change_functions, 2290 Frun_hook_with_args (4, args);
2302 4, args);
2303 2291
2304 /* "Unbind" the variables we "bound" to nil. Beware a 2292 /* There was no error: unarm the reset_on_error. */
2305 buffer-local hook which changes the buffer when run (e.g. W3). */ 2293 XSETCDR (rvoe_arg, Qt);
2306 if (old != current_buffer)
2307 {
2308 new = current_buffer;
2309 set_buffer_internal (old);
2310 Vbefore_change_functions = before_change_functions;
2311 Vafter_change_functions = after_change_functions;
2312 set_buffer_internal (new);
2313 }
2314 else
2315 {
2316 Vbefore_change_functions = before_change_functions;
2317 Vafter_change_functions = after_change_functions;
2318 }
2319 UNGCPRO;
2320 } 2294 }
2321 2295
2322 if (current_buffer->overlays_before || current_buffer->overlays_after) 2296 if (current_buffer->overlays_before || current_buffer->overlays_after)
@@ -2332,6 +2306,8 @@ signal_after_change (charpos, lendel, lenins)
2332 if (lendel == 0) 2306 if (lendel == 0)
2333 report_interval_modification (make_number (charpos), 2307 report_interval_modification (make_number (charpos),
2334 make_number (charpos + lenins)); 2308 make_number (charpos + lenins));
2309
2310 unbind_to (count, Qnil);
2335} 2311}
2336 2312
2337Lisp_Object 2313Lisp_Object