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.
This commit is contained in:
Gregory Heytings 2022-07-16 19:06:38 +00:00
parent 9de00e5fda
commit e7b5912b23
7 changed files with 79 additions and 31 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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)

View file

@ -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;