Don't reset post-command-hook to nil upon error.
authorStefan Monnier <monnier@iro.umontreal.ca>
Mon, 28 Mar 2011 20:26:35 +0000 (16:26 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Mon, 28 Mar 2011 20:26:35 +0000 (16:26 -0400)
* src/eval.c (enum run_hooks_condition): Remove.
(funcall_nil, funcall_not): New functions.
(run_hook_with_args): Call each function through a `funcall' argument.
Remove `cond' argument, now redundant.
(Frun_hooks, Frun_hook_with_args, Frun_hook_with_args_until_success)
(Frun_hook_with_args_until_failure): Adjust accordingly.
(run_hook_wrapped_funcall, Frun_hook_wrapped): New functions.
* src/keyboard.c (safe_run_hook_funcall): New function.
(safe_run_hooks_1, safe_run_hooks_error, safe_run_hooks): On error,
don't set the hook to nil, but remove the offending function instead.
(Qcommand_hook_internal): Remove, unused.
(syms_of_keyboard): Don't initialize Qcommand_hook_internal nor define
Vcommand_hook_internal.
* doc/lispref/commands.texi (Command Overview): post-command-hook is not reset
to nil any more.

doc/lispref/ChangeLog
doc/lispref/commands.texi
etc/NEWS
src/ChangeLog
src/eval.c
src/keyboard.c
src/lisp.h

index c705aae..1eb3cfa 100644 (file)
@@ -1,3 +1,8 @@
+2011-03-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * commands.texi (Command Overview): post-command-hook is not reset to
+       nil any more.
+
 2011-03-19  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * strings.texi (String Conversion): Don't mention
index 4f8d554..eb42ddb 100644 (file)
@@ -91,8 +91,9 @@ and also when the command loop is first entered.  At that time,
 
   Quitting is suppressed while running @code{pre-command-hook} and
 @code{post-command-hook}.  If an error happens while executing one of
-these hooks, it terminates execution of the hook, and clears the hook
-variable to @code{nil} so as to prevent an infinite loop of errors.
+these hooks, it does not terminate execution of the hook; instead
+the error is silenced and the function in which the error occurred
+is removed from the hook.
 
   A request coming into the Emacs server (@pxref{Emacs Server,,,
 emacs, The GNU Emacs Manual}) runs these two hooks just as a keyboard
index c48af3a..969b1cd 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -748,6 +748,11 @@ sc.el, x-menu.el, rnews.el, rnewspost.el
 \f
 * Lisp changes in Emacs 24.1
 
+** pre/post-command-hook are not reset to nil upon error.
+Instead, the offending function is removed.
+
+** New low-level function run-hook-wrapped.
+
 ** byte-compile-disable-print-circle is obsolete.
 ** deferred-action-list and deferred-action-function are obsolete.
 ** Removed the stack-trace-on-error variable.
index 75b75ab..be55ef3 100644 (file)
@@ -1,3 +1,20 @@
+2011-03-28  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * keyboard.c (safe_run_hook_funcall): New function.
+       (safe_run_hooks_1, safe_run_hooks_error, safe_run_hooks): On error,
+       don't set the hook to nil, but remove the offending function instead.
+       (Qcommand_hook_internal): Remove, unused.
+       (syms_of_keyboard): Don't initialize Qcommand_hook_internal nor define
+       Vcommand_hook_internal.
+
+       * eval.c (enum run_hooks_condition): Remove.
+       (funcall_nil, funcall_not): New functions.
+       (run_hook_with_args): Call each function through a `funcall' argument.
+       Remove `cond' argument, now redundant.
+       (Frun_hooks, Frun_hook_with_args, Frun_hook_with_args_until_success)
+       (Frun_hook_with_args_until_failure): Adjust accordingly.
+       (run_hook_wrapped_funcall, Frun_hook_wrapped): New functions.
+
 2011-03-28  Juanma Barranquero  <lekktu@gmail.com>
 
        * dispextern.h (string_buffer_position): Remove declaration.
index f68274e..7587436 100644 (file)
@@ -30,19 +30,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "xterm.h"
 #endif
 
-/* This definition is duplicated in alloc.c and keyboard.c */
-/* Putting it in lisp.h makes cc bomb out! */
+/* This definition is duplicated in alloc.c and keyboard.c */
+/* Putting it in lisp.h makes cc bomb out!  */
 
 struct backtrace
 {
   struct backtrace *next;
   Lisp_Object *function;
-  Lisp_Object *args;   /* Points to vector of args. */
+  Lisp_Object *args;   /* Points to vector of args.  */
   int nargs;           /* Length of vector.
                           If nargs is UNEVALLED, args points to slot holding
-                          list of unevalled args */
+                          list of unevalled args */
   char evalargs;
-  /* Nonzero means call value of debugger when done with this operation. */
+  /* Nonzero means call value of debugger when done with this operation.  */
   char debug_on_exit;
 };
 
@@ -146,7 +146,7 @@ init_eval (void)
   when_entered_debugger = -1;
 }
 
-/* unwind-protect function used by call_debugger.  */
+/* Unwind-protect function used by call_debugger.  */
 
 static Lisp_Object
 restore_stack_limits (Lisp_Object data)
@@ -556,7 +556,7 @@ interactive_p (int exclude_subrs_p)
             || btp->nargs == UNEVALLED))
     btp = btp->next;
 
-  /* btp now points at the frame of the innermost function that isn't
+  /* `btp' now points at the frame of the innermost function that isn't
      a special form, ignoring frames for Finteractive_p and/or
      Fbytecode at the top.  If this frame is for a built-in function
      (such as load or eval-region) return nil.  */
@@ -564,7 +564,7 @@ interactive_p (int exclude_subrs_p)
   if (exclude_subrs_p && SUBRP (fun))
     return 0;
 
-  /* btp points to the frame of a Lisp function that called interactive-p.
+  /* `btp' points to the frame of a Lisp function that called interactive-p.
      Return t if that function was called interactively.  */
   if (btp && btp->next && EQ (*btp->next->function, Qcall_interactively))
     return 1;
@@ -965,11 +965,11 @@ usage: (let VARLIST BODY...)  */)
 
   varlist = Fcar (args);
 
-  /* Make space to hold the values to give the bound variables */
+  /* Make space to hold the values to give the bound variables */
   elt = Flength (varlist);
   SAFE_ALLOCA_LISP (temps, XFASTINT (elt));
 
-  /* Compute the values and store them in `temps' */
+  /* Compute the values and store them in `temps' */
 
   GCPRO2 (args, *temps);
   gcpro2.nvars = 0;
@@ -1072,7 +1072,7 @@ definitions to shadow the loaded ones for use in file byte-compilation.  */)
          /* SYM is not mentioned in ENVIRONMENT.
             Look at its function definition.  */
          if (EQ (def, Qunbound) || !CONSP (def))
-           /* Not defined or definition not suitable */
+           /* Not defined or definition not suitable */
            break;
          if (EQ (XCAR (def), Qautoload))
            {
@@ -1213,10 +1213,7 @@ unwind_to_catch (struct catchtag *catch, Lisp_Object value)
   byte_stack_list = catch->byte_stack;
   gcprolist = catch->gcpro;
 #ifdef DEBUG_GCPRO
-  if (gcprolist != 0)
-    gcpro_level = gcprolist->level + 1;
-  else
-    gcpro_level = 0;
+  gcpro_level = gcprolist ? gcprolist->level + 1 : gcpro_level = 0;
 #endif
   backtrace_list = catch->backlist;
   lisp_eval_depth = catch->lisp_eval_depth;
@@ -1824,7 +1821,7 @@ maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig, Lisp_Object data)
          ? debug_on_quit
          : wants_debugger (Vdebug_on_error, conditions))
       && ! skip_debugger (conditions, combined_data)
-      /* rms: what's this for? */
+      /* RMS: What's this for?  */
       && when_entered_debugger < num_nonmacro_input_events)
     {
       call_debugger (Fcons (Qerror, Fcons (combined_data, Qnil)));
@@ -1891,7 +1888,7 @@ find_handler_clause (Lisp_Object handlers, Lisp_Object conditions,
 }
 
 
-/* dump an error message; called like vprintf */
+/* Dump an error message; called like vprintf.  */
 void
 verror (const char *m, va_list ap)
 {
@@ -1928,7 +1925,7 @@ verror (const char *m, va_list ap)
 }
 
 
-/* dump an error message; called like printf */
+/* Dump an error message; called like printf.  */
 
 /* VARARGS 1 */
 void
@@ -2024,7 +2021,7 @@ this does nothing and returns nil.  */)
   CHECK_SYMBOL (function);
   CHECK_STRING (file);
 
-  /* If function is defined and not as an autoload, don't override */
+  /* If function is defined and not as an autoload, don't override */
   if (!EQ (XSYMBOL (function)->function, Qunbound)
       && !(CONSP (XSYMBOL (function)->function)
           && EQ (XCAR (XSYMBOL (function)->function), Qautoload)))
@@ -2159,7 +2156,7 @@ DEFUN ("eval", Feval, Seval, 1, 1, 0,
 
   backtrace.next = backtrace_list;
   backtrace_list = &backtrace;
-  backtrace.function = &original_fun; /* This also protects them from gc */
+  backtrace.function = &original_fun; /* This also protects them from gc */
   backtrace.args = &original_args;
   backtrace.nargs = UNEVALLED;
   backtrace.evalargs = 1;
@@ -2169,7 +2166,7 @@ DEFUN ("eval", Feval, Seval, 1, 1, 0,
     do_debug_on_call (Qt);
 
   /* At this point, only original_fun and original_args
-     have values that will be used below */
+     have values that will be used below */
  retry:
 
   /* Optimize for no indirection.  */
@@ -2190,8 +2187,9 @@ DEFUN ("eval", Feval, Seval, 1, 1, 0,
 
       CHECK_CONS_LIST ();
 
-      if (XINT (numargs) < XSUBR (fun)->min_args ||
-         (XSUBR (fun)->max_args >= 0 && XSUBR (fun)->max_args < XINT (numargs)))
+      if (XINT (numargs) < XSUBR (fun)->min_args
+         || (XSUBR (fun)->max_args >= 0
+             && XSUBR (fun)->max_args < XINT (numargs)))
        xsignal2 (Qwrong_number_of_arguments, original_fun, numargs);
 
       else if (XSUBR (fun)->max_args == UNEVALLED)
@@ -2201,7 +2199,7 @@ DEFUN ("eval", Feval, Seval, 1, 1, 0,
        }
       else if (XSUBR (fun)->max_args == MANY)
        {
-         /* Pass a vector of evaluated arguments */
+         /* Pass a vector of evaluated arguments */
          Lisp_Object *vals;
          register int argnum = 0;
          USE_SAFE_ALLOCA;
@@ -2364,7 +2362,7 @@ usage: (apply FUNCTION &rest ARGUMENTS)  */)
     fun = indirect_function (fun);
   if (EQ (fun, Qunbound))
     {
-      /* Let funcall get the error */
+      /* Let funcall get the error */
       fun = args[0];
       goto funcall;
     }
@@ -2373,11 +2371,11 @@ usage: (apply FUNCTION &rest ARGUMENTS)  */)
     {
       if (numargs < XSUBR (fun)->min_args
          || (XSUBR (fun)->max_args >= 0 && XSUBR (fun)->max_args < numargs))
-       goto funcall;           /* Let funcall get the error */
+       goto funcall;           /* Let funcall get the error */
       else if (XSUBR (fun)->max_args > numargs)
        {
          /* Avoid making funcall cons up a yet another new vector of arguments
-            by explicitly supplying nil's for optional values */
+            by explicitly supplying nil's for optional values */
          SAFE_ALLOCA_LISP (funcall_args, 1 + XSUBR (fun)->max_args);
          for (i = numargs; i < XSUBR (fun)->max_args;)
            funcall_args[++i] = Qnil;
@@ -2415,9 +2413,16 @@ usage: (apply FUNCTION &rest ARGUMENTS)  */)
 \f
 /* Run hook variables in various ways.  */
 
-enum run_hooks_condition {to_completion, until_success, until_failure};
-static Lisp_Object run_hook_with_args (int, Lisp_Object *,
-                                      enum run_hooks_condition);
+Lisp_Object run_hook_with_args (int, Lisp_Object *,
+                               Lisp_Object (*funcall)
+                               (int nargs, Lisp_Object *args));
+
+static Lisp_Object
+funcall_nil (int nargs, Lisp_Object *args)
+{
+  Ffuncall (nargs, args);
+  return Qnil;
+}
 
 DEFUN ("run-hooks", Frun_hooks, Srun_hooks, 0, MANY, 0,
        doc: /* Run each hook in HOOKS.
@@ -2442,7 +2447,7 @@ usage: (run-hooks &rest HOOKS)  */)
   for (i = 0; i < nargs; i++)
     {
       hook[0] = args[i];
-      run_hook_with_args (1, hook, to_completion);
+      run_hook_with_args (1, hook, funcall_nil);
     }
 
   return Qnil;
@@ -2465,7 +2470,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument.
 usage: (run-hook-with-args HOOK &rest ARGS)  */)
   (int nargs, Lisp_Object *args)
 {
-  return run_hook_with_args (nargs, args, to_completion);
+  return run_hook_with_args (nargs, args, funcall_nil);
 }
 
 DEFUN ("run-hook-with-args-until-success", Frun_hook_with_args_until_success,
@@ -2485,7 +2490,13 @@ Instead, use `add-hook' and specify t for the LOCAL argument.
 usage: (run-hook-with-args-until-success HOOK &rest ARGS)  */)
   (int nargs, Lisp_Object *args)
 {
-  return run_hook_with_args (nargs, args, until_success);
+  return run_hook_with_args (nargs, args, Ffuncall);
+}
+
+static Lisp_Object
+funcall_not (int nargs, Lisp_Object *args)
+{
+  return NILP (Ffuncall (nargs, args)) ? Qt : Qnil;
 }
 
 DEFUN ("run-hook-with-args-until-failure", Frun_hook_with_args_until_failure,
@@ -2504,21 +2515,45 @@ Instead, use `add-hook' and specify t for the LOCAL argument.
 usage: (run-hook-with-args-until-failure HOOK &rest ARGS)  */)
   (int nargs, Lisp_Object *args)
 {
-  return run_hook_with_args (nargs, args, until_failure);
+  return NILP (run_hook_with_args (nargs, args, funcall_not)) ? Qt : Qnil;
 }
 
+static Lisp_Object
+run_hook_wrapped_funcall (int nargs, Lisp_Object *args)
+{
+  Lisp_Object tmp = args[0], ret;
+  args[0] = args[1];
+  args[1] = tmp;
+  ret = Ffuncall (nargs, args);
+  args[1] = args[0];
+  args[0] = tmp;
+  return ret;
+}
+
+DEFUN ("run-hook-wrapped", Frun_hook_wrapped, Srun_hook_wrapped, 2, MANY, 0,
+       doc: /* Run HOOK, passing each function through WRAP-FUNCTION.
+I.e. instead of calling each function FUN directly with arguments ARGS,
+it calls WRAP-FUNCTION with arguments FUN and ARGS.
+As soon as a call to WRAP-FUNCTION returns non-nil, `run-hook-wrapped'
+aborts and returns that value.
+usage: (run-hook-wrapped HOOK WRAP-FUNCTION &rest ARGS)  */)
+     (int nargs, Lisp_Object *args)
+{
+  return run_hook_with_args (nargs, args, run_hook_wrapped_funcall);
+}
+     
 /* ARGS[0] should be a hook symbol.
    Call each of the functions in the hook value, passing each of them
    as arguments all the rest of ARGS (all NARGS - 1 elements).
-   COND specifies a condition to test after each call
-   to decide whether to stop.
+   FUNCALL specifies how to call each function on the hook.
    The caller (or its caller, etc) must gcpro all of ARGS,
    except that it isn't necessary to gcpro ARGS[0].  */
 
-static Lisp_Object
-run_hook_with_args (int nargs, Lisp_Object *args, enum run_hooks_condition cond)
+Lisp_Object
+run_hook_with_args (int nargs, Lisp_Object *args,
+                   Lisp_Object (*funcall) (int nargs, Lisp_Object *args))
 {
-  Lisp_Object sym, val, ret;
+  Lisp_Object sym, val, ret = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   /* If we are dying or still initializing,
@@ -2528,14 +2563,13 @@ run_hook_with_args (int nargs, Lisp_Object *args, enum run_hooks_condition cond)
 
   sym = args[0];
   val = find_symbol_value (sym);
-  ret = (cond == until_failure ? Qt : Qnil);
 
   if (EQ (val, Qunbound) || NILP (val))
     return ret;
   else if (!CONSP (val) || EQ (XCAR (val), Qlambda))
     {
       args[0] = val;
-      return Ffuncall (nargs, args);
+      return funcall (nargs, args);
     }
   else
     {
@@ -2543,9 +2577,7 @@ run_hook_with_args (int nargs, Lisp_Object *args, enum run_hooks_condition cond)
       GCPRO3 (sym, val, global_vals);
 
       for (;
-          CONSP (val) && ((cond == to_completion)
-                          || (cond == until_success ? NILP (ret)
-                              : !NILP (ret)));
+          CONSP (val) && NILP (ret);
           val = XCDR (val))
        {
          if (EQ (XCAR (val), Qt))
@@ -2558,30 +2590,26 @@ run_hook_with_args (int nargs, Lisp_Object *args, enum run_hooks_condition cond)
              if (!CONSP (global_vals) || EQ (XCAR (global_vals), Qlambda))
                {
                  args[0] = global_vals;
-                 ret = Ffuncall (nargs, args);
+                 ret = funcall (nargs, args);
                }
              else
                {
                  for (;
-                      (CONSP (global_vals)
-                       && (cond == to_completion
-                           || (cond == until_success
-                               ? NILP (ret)
-                               : !NILP (ret))));
+                      CONSP (global_vals) && NILP (ret);
                       global_vals = XCDR (global_vals))
                    {
                      args[0] = XCAR (global_vals);
                      /* In a global value, t should not occur.  If it does, we
                         must ignore it to avoid an endless loop.  */
                      if (!EQ (args[0], Qt))
-                       ret = Ffuncall (nargs, args);
+                       ret = funcall (nargs, args);
                    }
                }
            }
          else
            {
              args[0] = XCAR (val);
-             ret = Ffuncall (nargs, args);
+             ret = funcall (nargs, args);
            }
        }
 
@@ -2603,7 +2631,7 @@ run_hook_with_args_2 (Lisp_Object hook, Lisp_Object arg1, Lisp_Object arg2)
   Frun_hook_with_args (3, temp);
 }
 \f
-/* Apply fn to arg */
+/* Apply fn to arg */
 Lisp_Object
 apply1 (Lisp_Object fn, Lisp_Object arg)
 {
@@ -2622,7 +2650,7 @@ apply1 (Lisp_Object fn, Lisp_Object arg)
   }
 }
 
-/* Call function fn on no arguments */
+/* Call function fn on no arguments */
 Lisp_Object
 call0 (Lisp_Object fn)
 {
@@ -2632,7 +2660,7 @@ call0 (Lisp_Object fn)
   RETURN_UNGCPRO (Ffuncall (1, &fn));
 }
 
-/* Call function fn with 1 argument arg1 */
+/* Call function fn with 1 argument arg1 */
 /* ARGSUSED */
 Lisp_Object
 call1 (Lisp_Object fn, Lisp_Object arg1)
@@ -2647,7 +2675,7 @@ call1 (Lisp_Object fn, Lisp_Object arg1)
   RETURN_UNGCPRO (Ffuncall (2, args));
 }
 
-/* Call function fn with 2 arguments arg1, arg2 */
+/* Call function fn with 2 arguments arg1, arg2 */
 /* ARGSUSED */
 Lisp_Object
 call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
@@ -2662,7 +2690,7 @@ call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
   RETURN_UNGCPRO (Ffuncall (3, args));
 }
 
-/* Call function fn with 3 arguments arg1, arg2, arg3 */
+/* Call function fn with 3 arguments arg1, arg2, arg3 */
 /* ARGSUSED */
 Lisp_Object
 call3 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3)
@@ -2678,7 +2706,7 @@ call3 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3)
   RETURN_UNGCPRO (Ffuncall (4, args));
 }
 
-/* Call function fn with 4 arguments arg1, arg2, arg3, arg4 */
+/* Call function fn with 4 arguments arg1, arg2, arg3, arg4 */
 /* ARGSUSED */
 Lisp_Object
 call4 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
@@ -2696,7 +2724,7 @@ call4 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
   RETURN_UNGCPRO (Ffuncall (5, args));
 }
 
-/* Call function fn with 5 arguments arg1, arg2, arg3, arg4, arg5 */
+/* Call function fn with 5 arguments arg1, arg2, arg3, arg4, arg5 */
 /* ARGSUSED */
 Lisp_Object
 call5 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
@@ -2715,7 +2743,7 @@ call5 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
   RETURN_UNGCPRO (Ffuncall (6, args));
 }
 
-/* Call function fn with 6 arguments arg1, arg2, arg3, arg4, arg5, arg6 */
+/* Call function fn with 6 arguments arg1, arg2, arg3, arg4, arg5, arg6 */
 /* ARGSUSED */
 Lisp_Object
 call6 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
@@ -2735,7 +2763,7 @@ call6 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
   RETURN_UNGCPRO (Ffuncall (7, args));
 }
 
-/* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7 */
+/* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7 */
 /* ARGSUSED */
 Lisp_Object
 call7 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
@@ -3079,7 +3107,7 @@ grow_specpdl (void)
   specpdl_ptr = specpdl + count;
 }
 
-/* specpdl_ptr->symbol is a field which describes which variable is
+/* `specpdl_ptr->symbol' is a field which describes which variable is
    let-bound, so it can be properly undone when we unbind_to.
    It can have the following two shapes:
    - SYMBOL : if it's a plain symbol, it means that we have let-bound
@@ -3318,7 +3346,7 @@ Output stream used is value of `standard-output'.  */)
       else
        {
          tem = *backlist->function;
-         Fprin1 (tem, Qnil);   /* This can QUIT */
+         Fprin1 (tem, Qnil);   /* This can QUIT */
          write_string ("(", -1);
          if (backlist->nargs == MANY)
            {
@@ -3588,6 +3616,7 @@ The value the function returns is not used.  */);
   defsubr (&Srun_hook_with_args);
   defsubr (&Srun_hook_with_args_until_success);
   defsubr (&Srun_hook_with_args_until_failure);
+  defsubr (&Srun_hook_wrapped);
   defsubr (&Sfetch_bytecode);
   defsubr (&Sbacktrace_debug);
   defsubr (&Sbacktrace);
index 06f375e..3fea3df 100644 (file)
@@ -254,7 +254,6 @@ Lisp_Object Qecho_area_clear_hook;
 /* Hooks to run before and after each command.  */
 Lisp_Object Qpre_command_hook;
 Lisp_Object Qpost_command_hook;
-Lisp_Object Qcommand_hook_internal;
 
 Lisp_Object Qdeferred_action_function;
 
@@ -1815,20 +1814,63 @@ adjust_point_for_property (EMACS_INT last_pt, int modified)
 static Lisp_Object
 safe_run_hooks_1 (void)
 {
-  return Frun_hooks (1, &Vinhibit_quit);
+  eassert (CONSP (Vinhibit_quit));
+  return call0 (XCDR (Vinhibit_quit));
 }
 
-/* Subroutine for safe_run_hooks: handle an error by clearing out the hook.  */
+/* Subroutine for safe_run_hooks: handle an error by clearing out the function
+   from the hook.  */
 
 static Lisp_Object
-safe_run_hooks_error (Lisp_Object data)
+safe_run_hooks_error (Lisp_Object error_data)
+{
+  Lisp_Object hook
+    = CONSP (Vinhibit_quit) ? XCAR (Vinhibit_quit) : Vinhibit_quit;
+  Lisp_Object fun = CONSP (Vinhibit_quit) ? XCDR (Vinhibit_quit) : Qnil;
+  Lisp_Object args[4];
+  args[0] = build_string ("Error in %s (%s): %s");
+  args[1] = hook;
+  args[2] = fun;
+  args[3] = error_data;
+  Fmessage (4, args);
+  if (SYMBOLP (hook))
+    {
+      Lisp_Object val;
+      int found = 0;
+      Lisp_Object newval = Qnil;
+      for (val = find_symbol_value (hook); CONSP (val); val = XCDR (val))
+       if (EQ (fun, XCAR (val)))
+         found = 1;
+       else
+         newval = Fcons (XCAR (val), newval);
+      if (found)
+       return Fset (hook, Fnreverse (newval));
+      /* Not found in the local part of the hook.  Let's look at the global
+        part.  */
+      newval = Qnil;
+      for (val = (NILP (Fdefault_boundp (hook)) ? Qnil
+                 : Fdefault_value (hook));
+          CONSP (val); val = XCDR (val))
+       if (EQ (fun, XCAR (val)))
+         found = 1;
+       else
+         newval = Fcons (XCAR (val), newval);
+      if (found)
+       return Fset_default (hook, Fnreverse (newval));
+    }
+  return Qnil;
+}
+
+static Lisp_Object
+safe_run_hook_funcall (int nargs, Lisp_Object *args)
 {
-  Lisp_Object args[3];
-  args[0] = build_string ("Error in %s: %s");
-  args[1] = Vinhibit_quit;
-  args[2] = data;
-  Fmessage (3, args);
-  return Fset (Vinhibit_quit, Qnil);
+  eassert (nargs == 1);
+  if (CONSP (Vinhibit_quit))
+    XSETCDR (Vinhibit_quit, args[0]);
+  else
+    Vinhibit_quit = Fcons (Vinhibit_quit, args[0]);
+
+  return internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
 }
 
 /* If we get an error while running the hook, cause the hook variable
@@ -1838,10 +1880,13 @@ safe_run_hooks_error (Lisp_Object data)
 void
 safe_run_hooks (Lisp_Object hook)
 {
+  /* FIXME: our `internal_condition_case' does not provide any way to pass data
+     to its body or to its handlers other than via globals such as
+     dynamically-bound variables ;-)  */
   int count = SPECPDL_INDEX ();
   specbind (Qinhibit_quit, hook);
 
-  internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
+  run_hook_with_args (1, &hook, safe_run_hook_funcall);
 
   unbind_to (count, Qnil);
 }
@@ -11438,9 +11483,6 @@ syms_of_keyboard (void)
   Qdeferred_action_function = intern_c_string ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
-  Qcommand_hook_internal = intern_c_string ("command-hook-internal");
-  staticpro (&Qcommand_hook_internal);
-
   Qfunction_key = intern_c_string ("function-key");
   staticpro (&Qfunction_key);
   Qmouse_click = intern_c_string ("mouse-click");
@@ -11908,22 +11950,18 @@ Buffer modification stores t in this variable.  */);
   Qdeactivate_mark = intern_c_string ("deactivate-mark");
   staticpro (&Qdeactivate_mark);
 
-  DEFVAR_LISP ("command-hook-internal", Vcommand_hook_internal,
-              doc: /* Temporary storage of `pre-command-hook' or `post-command-hook'.  */);
-  Vcommand_hook_internal = Qnil;
-
   DEFVAR_LISP ("pre-command-hook", Vpre_command_hook,
               doc: /* Normal hook run before each command is executed.
 If an unhandled error happens in running this hook,
-the hook value is set to nil, since otherwise the error
-might happen repeatedly and make Emacs nonfunctional.  */);
+the function in which the error occurred is unconditionally removed, since
+otherwise the error might happen repeatedly and make Emacs nonfunctional.  */);
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", Vpost_command_hook,
               doc: /* Normal hook run after each command is executed.
 If an unhandled error happens in running this hook,
-the hook value is set to nil, since otherwise the error
-might happen repeatedly and make Emacs nonfunctional.  */);
+the function in which the error occurred is unconditionally removed, since
+otherwise the error might happen repeatedly and make Emacs nonfunctional.  */);
   Vpost_command_hook = Qnil;
 
 #if 0
index 8c7d4da..1e255df 100644 (file)
@@ -2278,7 +2278,7 @@ void staticpro (Lisp_Object *);
 struct window;
 struct frame;
 
-/* Defined in data.c */
+/* Defined in data.c */
 extern Lisp_Object Qnil, Qt, Qquote, Qlambda, Qsubr, Qunbound;
 extern Lisp_Object Qerror_conditions, Qerror_message, Qtop_level;
 extern Lisp_Object Qerror, Qquit, Qwrong_type_argument, Qargs_out_of_range;
@@ -2812,7 +2812,7 @@ extern void init_obarray (void);
 extern void init_lread (void);
 extern void syms_of_lread (void);
 
-/* Defined in eval.c */
+/* Defined in eval.c */
 extern Lisp_Object Qautoload, Qexit, Qinteractive, Qcommandp, Qdefun, Qmacro;
 extern Lisp_Object Qinhibit_quit;
 extern Lisp_Object Vautoload_queue;
@@ -2830,6 +2830,9 @@ EXFUN (Frun_hooks, MANY);
 EXFUN (Frun_hook_with_args, MANY);
 EXFUN (Frun_hook_with_args_until_failure, MANY);
 extern void run_hook_with_args_2 (Lisp_Object, Lisp_Object, Lisp_Object);
+extern Lisp_Object run_hook_with_args (int nargs, Lisp_Object *args,
+                                      Lisp_Object (*funcall)
+                                      (int nargs, Lisp_Object *args));
 EXFUN (Fprogn, UNEVALLED);
 EXFUN (Finteractive_p, 0);
 EXFUN (Fthrow, 2) NO_RETURN;