From 5e296283f57b21e962e6e6860e448905f99f281e Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Sun, 31 Jul 2022 20:32:15 +0000 Subject: [PATCH 01/10] 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); From 43a174f62c50871c0bcb6e4b15144a177f028218 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Sun, 31 Jul 2022 22:36:55 +0000 Subject: [PATCH 02/10] Move the computation of narrowing bounds for long line optimizations. * src/xdisp.c (init_iterator): Move the computation from here... (reseat): ... to here. Also recompute the position in certain cases. --- src/xdisp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 88a489e290f..8a19b3bda97 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3413,12 +3413,6 @@ init_iterator (struct it *it, struct window *w, } } - if (current_buffer->long_line_optimizations_p) - { - it->narrowed_begv = get_narrowed_begv (w, window_point (w)); - it->narrowed_zv = get_narrowed_zv (w, window_point (w)); - } - /* If a buffer position was specified, set the iterator there, getting overlays and face properties from that position. */ if (charpos >= BUF_BEG (current_buffer)) @@ -7532,6 +7526,17 @@ reseat (struct it *it, struct text_pos pos, bool force_p) reseat_1 (it, pos, false); + if (current_buffer->long_line_optimizations_p) + { + if (!it->narrowed_begv + || ((pos.charpos < it->narrowed_begv || pos.charpos > it->narrowed_zv) + && (!redisplaying_p || it->line_wrap == TRUNCATE))) + { + it->narrowed_begv = get_narrowed_begv (it->w, window_point (it->w)); + it->narrowed_zv = get_narrowed_zv (it->w, window_point (it->w)); + } + } + /* Determine where to check text properties. Avoid doing it where possible because text property lookup is very expensive. */ if (force_p From d0e4ec3c29abc61a92c40d89fc7d3e3cc452e934 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Mon, 1 Aug 2022 13:27:02 +0000 Subject: [PATCH 03/10] Fix forgotten initialization for long line optimizations. * src/xdisp.c (init_iterator): Initialize the 'narrowed_begv' field. * src/buffer.c (syms_of_buffer): Docstring clarification. --- src/buffer.c | 5 ++++- src/xdisp.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/buffer.c b/src/buffer.c index a07194aef72..e5601af5051 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -6431,12 +6431,15 @@ will run for `clone-indirect-buffer' calls as well. */); DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold, doc: /* Line length above which to use redisplay shortcuts. + The value should be a positive integer or nil. If the value is an integer, shortcuts in the display code intended to speed up redisplay for long lines will automatically be enabled in buffers which contain one or more lines whose length is above this threshold. -If nil, these display shortcuts will always remain disabled. */); +If nil, these display shortcuts will always remain disabled. + +There is no reason to change that value except for debugging purposes. */); XSETFASTINT (Vlong_line_threshold, 10000); defsubr (&Sbuffer_live_p); diff --git a/src/xdisp.c b/src/xdisp.c index 8a19b3bda97..9574d06bd5c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3472,6 +3472,9 @@ init_iterator (struct it *it, struct window *w, &it->bidi_it); } + if (current_buffer->long_line_optimizations_p) + it->narrowed_begv = 0; + /* Compute faces etc. */ reseat (it, it->current.pos, true); } From 38d970b748a23d3b8dad6feef8e392f1d6d3c9e5 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Mon, 1 Aug 2022 15:01:15 +0000 Subject: [PATCH 04/10] ; * src/xdisp.c (reseat): Improve recomputations. --- src/xdisp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 9574d06bd5c..c6fc05b8b4a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -7531,13 +7531,17 @@ reseat (struct it *it, struct text_pos pos, bool force_p) if (current_buffer->long_line_optimizations_p) { - if (!it->narrowed_begv - || ((pos.charpos < it->narrowed_begv || pos.charpos > it->narrowed_zv) - && (!redisplaying_p || it->line_wrap == TRUNCATE))) + if (!it->narrowed_begv) { it->narrowed_begv = get_narrowed_begv (it->w, window_point (it->w)); it->narrowed_zv = get_narrowed_zv (it->w, window_point (it->w)); } + else if ((pos.charpos < it->narrowed_begv || pos.charpos > it->narrowed_zv) + && (!redisplaying_p || it->line_wrap == TRUNCATE)) + { + it->narrowed_begv = get_narrowed_begv (it->w, pos.charpos); + it->narrowed_zv = get_narrowed_zv (it->w, pos.charpos); + } } /* Determine where to check text properties. Avoid doing it From 5dc65c10ca1a2504699ad5374fedb127960946c8 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Mon, 1 Aug 2022 15:52:12 +0000 Subject: [PATCH 05/10] Various improvements to long lines handling. * src/xdisp.c (get_visually_first_element, (move_it_vertically_backward): Do not go back too far with bidi. (get_narrowed_begv): Do not return 0 anymore instead of BEGV. (handle_fontified_prop): Simplify accordingly. * src/keyboard.c (safe_run_hooks_maybe_narrowed): Simplify accordingly. * src/composite.c (find_automatic_composition): Ditto. --- src/composite.c | 2 +- src/keyboard.c | 9 +++------ src/xdisp.c | 11 ++++------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/composite.c b/src/composite.c index 0f90b92a785..e721fe8c81f 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1600,7 +1600,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, /* In buffers with very long lines, this function becomes very slow. Pretend that the buffer is narrowed to make it fast. */ narrowed_begv = get_narrowed_begv (w, window_point (w)); - if (narrowed_begv && pos > narrowed_begv) + if (pos > narrowed_begv) head = narrowed_begv; tail = ZV; stop = GPT; diff --git a/src/keyboard.c b/src/keyboard.c index 094119340e1..a730dfe4fda 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1907,12 +1907,9 @@ safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w) 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); - } + Fnarrow_to_region (make_fixnum (get_narrowed_begv (w, PT)), + make_fixnum (get_narrowed_zv (w, PT)), + Qt); run_hook_with_args (2, ((Lisp_Object []) {hook, hook}), safe_run_hook_funcall); unbind_to (count, Qnil); diff --git a/src/xdisp.c b/src/xdisp.c index c6fc05b8b4a..c4abe6e9855 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3507,9 +3507,7 @@ ptrdiff_t get_narrowed_begv (struct window *w, ptrdiff_t pos) { int len = get_narrowed_len (w); - ptrdiff_t begv; - begv = max ((pos / len - 1) * len, BEGV); - return begv == BEGV ? 0 : begv; + return max ((pos / len - 1) * len, BEGV); } ptrdiff_t @@ -4394,13 +4392,12 @@ handle_fontified_prop (struct it *it) if (current_buffer->long_line_optimizations_p) { - ptrdiff_t begv = it->narrowed_begv ? it->narrowed_begv : BEGV; + ptrdiff_t begv = it->narrowed_begv; ptrdiff_t zv = it->narrowed_zv; ptrdiff_t charpos = IT_CHARPOS (*it); if (charpos < begv || charpos > zv) { begv = get_narrowed_begv (it->w, charpos); - if (!begv) begv = BEGV; zv = get_narrowed_zv (it->w, charpos); } Fnarrow_to_region (make_fixnum (begv), make_fixnum (zv), Qt); @@ -8894,7 +8891,7 @@ get_visually_first_element (struct it *it) find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it), -1, &it->bidi_it.bytepos), - it->narrowed_begv); + get_closer_narrowed_begv (it->w, IT_CHARPOS (*it))); bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true); do { @@ -10784,7 +10781,7 @@ move_it_vertically_backward (struct it *it, int dy) dec_both (&cp, &bp); SET_WITH_NARROWED_BEGV (it, cp, find_newline_no_quit (cp, bp, -1, NULL), - it->narrowed_begv); + get_closer_narrowed_begv (it->w, IT_CHARPOS (*it))); move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS); } bidi_unshelve_cache (it3data, true); From e0870fb8742d8f4fd4d2fc0ede6b4b6ae1036c38 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 1 Aug 2022 19:13:16 +0300 Subject: [PATCH 06/10] * src/xdisp.c (get_visually_first_element): Fix a typo. --- src/xdisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xdisp.c b/src/xdisp.c index c4abe6e9855..264fbaea59d 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -8846,7 +8846,7 @@ get_visually_first_element (struct it *it) SET_WITH_NARROWED_BEGV (it, bob, string_p ? 0 : - IT_BYTEPOS (*it) < BEGV ? obegv : BEGV, + IT_CHARPOS (*it) < BEGV ? obegv : BEGV, it->narrowed_begv); if (STRINGP (it->string)) From c6b5726130e9c3c297747a47c267dad5e8da4f52 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Mon, 1 Aug 2022 16:46:09 +0000 Subject: [PATCH 07/10] ; * src/xdisp.c (get_visually_first_element): Fix last change. --- src/xdisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xdisp.c b/src/xdisp.c index 264fbaea59d..7d62c7823ed 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -8891,7 +8891,7 @@ get_visually_first_element (struct it *it) find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it), -1, &it->bidi_it.bytepos), - get_closer_narrowed_begv (it->w, IT_CHARPOS (*it))); + it->narrowed_begv); bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true); do { From 82b602dc2f52775a4082d24d64380867da051350 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Thu, 4 Aug 2022 09:01:55 +0000 Subject: [PATCH 08/10] Improve Bidi with long lines. * src/composite.c (composition_compute_stop_pos): Use an 'endpos' that is not too far away. (find_automatic_composition): Use a 'head' that is not too far away. Also make sure that this code path is not taken when long line optimizations are disabled. * src/dispextern.h (struct composition_it): Add a field that points to the parent iterator. * src/xdisp.c (init_iterator): Set it. --- src/composite.c | 20 +++++++++++++------- src/dispextern.h | 2 ++ src/xdisp.c | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/composite.c b/src/composite.c index e721fe8c81f..9e641722cac 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1021,7 +1021,11 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos, /* But we don't know where to stop the searching. */ endpos = NILP (string) ? BEGV - 1 : -1; /* Usually we don't reach ENDPOS because we stop searching - at an uncomposable character (NL, LRE, etc). */ + at an uncomposable character (NL, LRE, etc). In buffers + with long lines, however, NL might be far away, so + pretend that the buffer is smaller. */ + if (current_buffer->long_line_optimizations_p) + endpos = get_closer_narrowed_begv (cmp_it->parent_it->w, charpos); } } cmp_it->id = -1; @@ -1580,7 +1584,6 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, Lisp_Object window; struct window *w; bool need_adjustment = 0; - ptrdiff_t narrowed_begv; window = Fget_buffer_window (Fcurrent_buffer (), Qnil); if (NILP (window)) @@ -1597,11 +1600,14 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, } else head = backlim; - /* In buffers with very long lines, this function becomes very - slow. Pretend that the buffer is narrowed to make it fast. */ - narrowed_begv = get_narrowed_begv (w, window_point (w)); - if (pos > narrowed_begv) - head = narrowed_begv; + if (current_buffer->long_line_optimizations_p) + { + /* In buffers with very long lines, this function becomes very + slow. Pretend that the buffer is narrowed to make it fast. */ + ptrdiff_t begv = get_closer_narrowed_begv (w, window_point (w)); + if (pos > begv) + head = narrowed_begv; + } tail = ZV; stop = GPT; cur.pos_byte = CHAR_TO_BYTE (cur.pos); diff --git a/src/dispextern.h b/src/dispextern.h index 037e02ff58f..12ba927261f 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2287,6 +2287,8 @@ struct composition_it reverse order, and thus the grapheme clusters must be rendered from the last to the first. */ bool reversed_p; + /* Parent iterator. */ + struct it *parent_it; /** The following members contain information about the current grapheme cluster. */ diff --git a/src/xdisp.c b/src/xdisp.c index 7d62c7823ed..12f56227e46 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3229,6 +3229,7 @@ init_iterator (struct it *it, struct window *w, it->f = XFRAME (w->frame); it->cmp_it.id = -1; + it->cmp_it.parent_it = it; if (max_redisplay_ticks > 0) update_redisplay_ticks (0, w); From 5e33712672035473fd74e8da637b77dbf9a4eb31 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 4 Aug 2022 12:47:32 +0300 Subject: [PATCH 09/10] ; * src/composite.c (find_automatic_composition): Fix a typo. --- src/composite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/composite.c b/src/composite.c index 9e641722cac..a13839939b8 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1606,7 +1606,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, slow. Pretend that the buffer is narrowed to make it fast. */ ptrdiff_t begv = get_closer_narrowed_begv (w, window_point (w)); if (pos > begv) - head = narrowed_begv; + head = begv; } tail = ZV; stop = GPT; From a95c5baa6a556059a434b9973a4454d414c15928 Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Thu, 4 Aug 2022 11:57:27 +0000 Subject: [PATCH 10/10] ; * src/keyboard.c (safe_run_hooks_maybe_narrowed): Fix broken merge. --- src/keyboard.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index a730dfe4fda..02e02448ff8 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1907,9 +1907,9 @@ safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w) specbind (Qinhibit_quit, Qt); if (current_buffer->long_line_optimizations_p) - Fnarrow_to_region (make_fixnum (get_narrowed_begv (w, PT)), - make_fixnum (get_narrowed_zv (w, PT)), - Qt); + narrow_to_region_internal (make_fixnum (get_narrowed_begv (w, PT)), + make_fixnum (get_narrowed_zv (w, PT)), + true); run_hook_with_args (2, ((Lisp_Object []) {hook, hook}), safe_run_hook_funcall); unbind_to (count, Qnil);