From e7b5912b235936b304701ba6b1e808d9b197fd4f Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Sat, 16 Jul 2022 19:06:38 +0000 Subject: [PATCH] Improvements to long lines handling. * src/buffer.h (struct buffer): New field 'long_line_optimizations_p'. * src/buffer.c (syms_of_buffer): New variable 'long-line-threshold'. (reset_buffer): Initialize the 'long_line_optimizations_p' field. (Fbuffer_swap_text): Handle it. * src/xdisp.c (redisplay_window): Set 'long_line_optimizations_p' when a buffer contains long lines. (init_iterator): Use 'long_line_optimizations_p'. (get_narrowed_begv): Update. (SET_WITH_NARROWED_BEGV): New macro. (unwind_narrowed_begv): New internal function used by the new macro. (back_to_previous_line_start, get_visually_first_element, move_it_vertically_backward): Use the new macro. * src/search.c (find_newline1): Make it externally visible. * src/lisp.h: Make 'find_newline1' externally visible. * src/dispextern.h (struct it): Update comment. Remove the 'WITH_NARROWED_BEGV' macro. * etc/NEWS: Mention the 'long-line-threshold' variable. --- etc/NEWS | 4 ++- src/buffer.c | 10 +++++++ src/buffer.h | 4 +++ src/dispextern.h | 16 ++--------- src/lisp.h | 2 ++ src/search.c | 2 +- src/xdisp.c | 72 ++++++++++++++++++++++++++++++++++++++---------- 7 files changed, 79 insertions(+), 31 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 223e6dd7616..6050a8ae1ae 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -332,7 +332,9 @@ experience slowdowns while editing files with long lines, this is either due to font locking, which you can turn off with M-x font-lock-mode, or to the current major mode or one of the enabled minor modes, in which case you should open the the file with M-x -find-file-literally instead of C-x C-f. +find-file-literally instead of C-x C-f. The variable +'long-line-threshold' controls whether and when these display +optimizations are used. +++ ** New command to change the font size globally. diff --git a/src/buffer.c b/src/buffer.c index 509ce51b55e..a777668e44b 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -984,6 +984,7 @@ reset_buffer (register struct buffer *b) /* It is more conservative to start out "changed" than "unchanged". */ b->clip_changed = 0; b->prevent_redisplay_optimizations_p = 1; + b->long_line_optimizations_p = 0; bset_backed_up (b, Qnil); bset_local_minor_modes (b, Qnil); BUF_AUTOSAVE_MODIFF (b) = 0; @@ -2445,6 +2446,7 @@ results, see Info node `(elisp)Swapping Text'. */) swapfield (bidi_paragraph_cache, struct region_cache *); current_buffer->prevent_redisplay_optimizations_p = 1; other_buffer->prevent_redisplay_optimizations_p = 1; + swapfield (long_line_optimizations_p, bool_bf); swapfield (overlays_before, struct Lisp_Overlay *); swapfield (overlays_after, struct Lisp_Overlay *); swapfield (overlay_center, ptrdiff_t); @@ -6423,6 +6425,14 @@ Since `clone-indirect-buffer' calls `make-indirect-buffer', this hook will run for `clone-indirect-buffer' calls as well. */); Vclone_indirect_buffer_hook = Qnil; + DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold, + doc: /* Line length above which specific display optimizations are used. +Display optimizations for long lines will automatically be enabled in +buffers which contain one or more lines whose length is above that +threshold. +When nil, these display optimizations are disabled. */); + XSETFASTINT (Vlong_line_threshold, 10000); + defsubr (&Sbuffer_live_p); defsubr (&Sbuffer_list); defsubr (&Sget_buffer); diff --git a/src/buffer.h b/src/buffer.h index 135eaf72d30..09daa29992a 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -681,6 +681,10 @@ struct buffer defined, as well as by with-temp-buffer, for example. */ bool_bf inhibit_buffer_hooks : 1; + /* Non-zero when the buffer contains long lines and specific + display optimizations must be used. */ + bool_bf long_line_optimizations_p : 1; + /* List of overlays that end at or before the current center, in order of end-position. */ struct Lisp_Overlay *overlays_before; diff --git a/src/dispextern.h b/src/dispextern.h index 2edf4b73f81..c5794994950 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2332,8 +2332,8 @@ struct it with which display_string was called. */ ptrdiff_t end_charpos; - /* Alternate begin position of the buffer, which is used to optimize - display (see the WITH_NARROWED_BEGV macro below). */ + /* Alternate begin position of the buffer that may be used to + optimize display (see the WITH_NARROWED_BEGV macro below). */ ptrdiff_t narrowed_begv; /* C string to iterate over. Non-null means get characters from @@ -2817,18 +2817,6 @@ struct it reset_box_start_end_flags ((IT)); \ } while (false) -/* Execute STATEMENT with a temporarily narrowed buffer. */ - -#define WITH_NARROWED_BEGV(STATEMENT) \ - do { \ - ptrdiff_t obegv = BEGV; \ - if (it->narrowed_begv) \ - SET_BUF_BEGV (current_buffer, it->narrowed_begv); \ - STATEMENT; \ - if (it->narrowed_begv) \ - SET_BUF_BEGV (current_buffer, obegv); \ - } while (0) - /* Bit-flags indicating what operation move_it_to should perform. */ enum move_operation_enum diff --git a/src/lisp.h b/src/lisp.h index e4a49b8ef94..5045d49e1b6 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4761,6 +4761,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case (Lisp_Object, const char *, ptrdiff_t); extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, Lisp_Object); +extern ptrdiff_t find_newline1 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, + ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool); extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool); extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, diff --git a/src/search.c b/src/search.c index 9d6bd074e1b..b5d6a442c0f 100644 --- a/src/search.c +++ b/src/search.c @@ -3192,7 +3192,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0, } /* Like find_newline, but doesn't use the cache, and only searches forward. */ -static ptrdiff_t +ptrdiff_t find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted, ptrdiff_t *bytepos, bool allow_quit) diff --git a/src/xdisp.c b/src/xdisp.c index ac76917eb3f..98bf15a8594 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3425,7 +3425,8 @@ init_iterator (struct it *it, struct window *w, } } - it->narrowed_begv = get_narrowed_begv (w); + if (current_buffer->long_line_optimizations_p) + it->narrowed_begv = get_narrowed_begv (w); /* If a buffer position was specified, set the iterator there, getting overlays and face properties from that position. */ @@ -3493,20 +3494,43 @@ init_iterator (struct it *it, struct window *w, CHECK_IT (it); } -/* Compute a suitable value for BEGV that can be used temporarily, to - optimize display, for the buffer in window W. */ +/* Compute a suitable alternate value for BEGV that may be used + temporarily to optimize display if the buffer in window W contains + long lines. */ ptrdiff_t get_narrowed_begv (struct window *w) { int len; ptrdiff_t begv; - len = (1 + ((window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) * - window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)) / - 10000)) * 10000; - begv = max ((PT / len - 2) * len, BEGV); + len = 3 * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) * + window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)); + begv = max ((window_point (w) / len - 1) * len, BEGV); return begv == BEGV ? 0 : begv; } +static void +unwind_narrowed_begv (Lisp_Object point_min) +{ + SET_BUF_BEGV (current_buffer, XFIXNUM (point_min)); +} + +/* Set DST to EXPR. When IT indicates that BEGV should temporarily be + updated to optimize display, evaluate EXPR with an updated BEGV. */ + +#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR) \ + do { \ + if (IT->narrowed_begv) \ + { \ + specpdl_ref count = SPECPDL_INDEX (); \ + record_unwind_protect (unwind_narrowed_begv, Fpoint_min ()); \ + SET_BUF_BEGV (current_buffer, IT->narrowed_begv); \ + DST = EXPR; \ + unbind_to (count, Qnil); \ + } \ + else \ + DST = EXPR; \ + } while (0) + /* Initialize IT for the display of window W with window start POS. */ void @@ -7007,8 +7031,8 @@ back_to_previous_line_start (struct it *it) ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it); dec_both (&cp, &bp); - WITH_NARROWED_BEGV (IT_CHARPOS (*it) = - find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it))); + SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it), + find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it))); } @@ -8642,7 +8666,7 @@ get_visually_first_element (struct it *it) ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV); ptrdiff_t bob; - WITH_NARROWED_BEGV (bob = (string_p ? 0 : BEGV)); + SET_WITH_NARROWED_BEGV (it, bob, string_p ? 0 : BEGV); if (STRINGP (it->string)) { @@ -8682,10 +8706,10 @@ get_visually_first_element (struct it *it) if (string_p) it->bidi_it.charpos = it->bidi_it.bytepos = 0; else - WITH_NARROWED_BEGV (it->bidi_it.charpos = - find_newline_no_quit (IT_CHARPOS (*it), - IT_BYTEPOS (*it), -1, - &it->bidi_it.bytepos)); + SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos, + find_newline_no_quit (IT_CHARPOS (*it), + IT_BYTEPOS (*it), -1, + &it->bidi_it.bytepos)); bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true); do { @@ -10603,7 +10627,8 @@ move_it_vertically_backward (struct it *it, int dy) ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it); dec_both (&cp, &bp); - WITH_NARROWED_BEGV (cp = find_newline_no_quit (cp, bp, -1, NULL)); + SET_WITH_NARROWED_BEGV (it, cp, + find_newline_no_quit (cp, bp, -1, NULL)); move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS); } bidi_unshelve_cache (it3data, true); @@ -19245,6 +19270,23 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) } } + /* Check whether the buffer to be displayed contains long lines. */ + if (!NILP (Vlong_line_threshold) + && !current_buffer->long_line_optimizations_p + && MODIFF != UNCHANGED_MODIFIED) + { + ptrdiff_t cur, next, found, max = 0; + for (cur = 1; cur < Z; cur = next) + { + next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1, + &found, NULL, true); + if (next - cur > max) max = next - cur; + if (!found || max > XFIXNUM (Vlong_line_threshold)) break; + } + if (max > XFIXNUM (Vlong_line_threshold)) + current_buffer->long_line_optimizations_p = true; + } + /* If window-start is screwed up, choose a new one. */ if (XMARKER (w->start)->buffer != current_buffer) goto recenter; -- 2.39.2