From 5e296283f57b21e962e6e6860e448905f99f281e Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Sun, 31 Jul 2022 20:32:15 +0000 Subject: [PATCH] Add locked narrowing around pre- and post-command-hook * src/keyboard.c (safe_run_hooks_maybe_narrowed): New function. (command_loop_1): Use it for 'pre-command-hook' and 'post-command-hook'. (syms_of_keyboard): Update docstrings of 'pre-command-hook' and 'post-command-hook'. * src/lisp.h: Prototype of the new function. --- src/keyboard.c | 57 ++++++++++++++++++++++++++++++++++++++++++-------- src/lisp.h | 1 + 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 2863058d633..094119340e1 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1295,7 +1295,8 @@ command_loop_1 (void) /* Note that the value cell will never directly contain nil if the symbol is a local variable. */ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks)) - safe_run_hooks (Qpost_command_hook); + safe_run_hooks_maybe_narrowed (Qpost_command_hook, + XWINDOW (selected_window)); /* If displaying a message, resize the echo area window to fit that message's size exactly. */ @@ -1461,7 +1462,9 @@ command_loop_1 (void) } Vthis_command = cmd; Vreal_this_command = cmd; - safe_run_hooks (Qpre_command_hook); + + safe_run_hooks_maybe_narrowed (Qpre_command_hook, + XWINDOW (selected_window)); already_adjusted = 0; @@ -1513,7 +1516,8 @@ command_loop_1 (void) } kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg); - safe_run_hooks (Qpost_command_hook); + safe_run_hooks_maybe_narrowed (Qpost_command_hook, + XWINDOW (selected_window)); /* If displaying a message, resize the echo area window to fit that message's size exactly. Do this only if the echo area @@ -1895,6 +1899,25 @@ safe_run_hooks (Lisp_Object hook) unbind_to (count, Qnil); } +void +safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w) +{ + specpdl_ref count = SPECPDL_INDEX (); + + specbind (Qinhibit_quit, Qt); + + if (current_buffer->long_line_optimizations_p) + { + ptrdiff_t begv = get_narrowed_begv (w, PT); + ptrdiff_t zv = get_narrowed_zv (w, PT); + if (!begv) begv = BEGV; + Fnarrow_to_region (make_fixnum (begv), make_fixnum (zv), Qt); + } + + run_hook_with_args (2, ((Lisp_Object []) {hook, hook}), safe_run_hook_funcall); + unbind_to (count, Qnil); +} + /* Nonzero means polling for input is temporarily suppressed. */ @@ -12622,23 +12645,39 @@ Buffer modification stores t in this variable. */); 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 function in which the error occurred is unconditionally removed, since -otherwise the error might happen repeatedly and make Emacs nonfunctional. + +If an unhandled error happens in running this hook, the function in +which the error occurred is unconditionally removed, since otherwise +the error might happen repeatedly and make Emacs nonfunctional. + +Note that, when the current buffer contains one or more lines whose +length is above `long-line-threshold', these hook functions are called +with the buffer narrowed to a small portion around point, and the +narrowing is locked (see `narrow-to-region'), so that these hook +functions cannot use `widen' to gain access to other portions of +buffer text. See also `post-command-hook'. */); 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 function in which the error occurred is unconditionally removed, since -otherwise the error might happen repeatedly and make Emacs nonfunctional. + +If an unhandled error happens in running this hook, the function in +which the error occurred is unconditionally removed, since otherwise +the error might happen repeatedly and make Emacs nonfunctional. It is a bad idea to use this hook for expensive processing. If unavoidable, wrap your code in `(while-no-input (redisplay) CODE)' to avoid making Emacs unresponsive while the user types. +Note that, when the current buffer contains one or more lines whose +length is above `long-line-threshold', these hook functions are called +with the buffer narrowed to a small portion around point, and the +narrowing is locked (see `narrow-to-region'), so that these hook +functions cannot use `widen' to gain access to other portions of +buffer text. + See also `pre-command-hook'. */); Vpost_command_hook = Qnil; diff --git a/src/lisp.h b/src/lisp.h index 8fcc9b6e75a..7136bb3dc1e 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4829,6 +4829,7 @@ extern bool detect_input_pending (void); extern bool detect_input_pending_ignore_squeezables (void); extern bool detect_input_pending_run_timers (bool); extern void safe_run_hooks (Lisp_Object); +extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *); extern void cmd_error_internal (Lisp_Object, const char *); extern Lisp_Object command_loop_2 (Lisp_Object); extern Lisp_Object read_menu_command (void); -- 2.39.5