1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-27 15:52:00 -08:00

Speed up scrolling when lines are very long and truncated

* src/window.c (window_scroll_for_long_lines): New function.
(window_scroll): Call 'window_scroll_for_long_lines' when lines
are very long and truncated on display.  Also, disable
'fontification-functions' during scrolling in that case.
* src/xdisp.c (redisplay_window): When recentering the window's
display, go back to the centering position using a simplified
method, if lines in the buffer are very long and truncated on
display.
This commit is contained in:
Eli Zaretskii 2022-10-11 13:26:01 +03:00
parent 163000fb59
commit 4f114c0d95
2 changed files with 106 additions and 6 deletions

View file

@ -52,6 +52,7 @@ static ptrdiff_t get_leaf_windows (struct window *, struct window **,
ptrdiff_t);
static void window_scroll_pixel_based (Lisp_Object, int, bool, bool);
static void window_scroll_line_based (Lisp_Object, int, bool, bool);
static void window_scroll_for_long_lines (struct window *, int, bool);
static void foreach_window (struct frame *,
bool (* fn) (struct window *, void *),
void *);
@ -5536,19 +5537,40 @@ window_internal_height (struct window *w)
static void
window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror)
{
struct window *w = XWINDOW (window);
struct buffer *b = XBUFFER (w->contents);
bool long_lines_truncated =
b->long_line_optimizations_p && !NILP (BVAR (b, truncate_lines));
specpdl_ref count = SPECPDL_INDEX ();
n = clip_to_bounds (INT_MIN, n, INT_MAX);
wset_redisplay (XWINDOW (window));
wset_redisplay (w);
if (whole && fast_but_imprecise_scrolling)
/* Does this window's buffer have very long and truncated lines? */
if (b->long_line_optimizations_p
&& !long_lines_truncated
&& !NILP (Vtruncate_partial_width_windows)
&& w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w))))
{
if (FIXNUMP (Vtruncate_partial_width_windows))
long_lines_truncated =
w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
else
long_lines_truncated = true;
}
if (whole && (fast_but_imprecise_scrolling || long_lines_truncated))
specbind (Qfontification_functions, Qnil);
/* On GUI frames, use the pixel-based version which is much slower
than the line-based one but can handle varying line heights. */
if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
if (whole && long_lines_truncated)
window_scroll_for_long_lines (w, n, noerror);
else if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
{
/* On GUI frames, use the pixel-based version which is much
slower than the line-based one, but can handle varying
line heights. */
record_unwind_protect_void (unwind_display_working_on_window);
display_working_on_window_p = true;
window_scroll_pixel_based (window, n, whole, noerror);
@ -5598,6 +5620,71 @@ sanitize_next_screen_context_lines (void)
return clip_to_bounds (0, next_screen_context_lines, 1000000);
}
/* Implementation of window_scroll for very long and truncated lines.
This is a simplified version, it only handles WHOLE window scrolls,
and doesn't honor scroll-preserve-screen-position nor scroll-margin. */
static void
window_scroll_for_long_lines (struct window *w, int n, bool noerror)
{
ptrdiff_t startpos = marker_position (w->start);
ptrdiff_t startbyte = marker_byte_position (w->start);
int nscls = sanitize_next_screen_context_lines ();
register int ht = window_internal_height (w);
n *= max (1, ht - nscls);
/* If point is not visible in window, bring it inside window. */
struct position pos;
int rtop, rbot, dummy_rowh, dummy_vpos, dummy_x, dummy_y;
if (!(PT >= startpos
&& PT <= ZV
&& startpos <= ZV
&& pos_visible_p (w, PT, &dummy_x, &dummy_y, &rtop, &rbot, &dummy_rowh,
&dummy_vpos)
&& !rtop && !rbot))
{
pos = *vmotion (PT, PT_BYTE, - (ht / 2), w);
startpos = pos.bufpos;
startbyte = pos.bytepos;
}
SET_PT_BOTH (startpos, startbyte);
bool lose = n < 0 && PT == BEGV;
pos = *vmotion (PT, PT_BYTE, n, w);
if (lose)
{
if (noerror)
return;
else
xsignal0 (Qbeginning_of_buffer);
}
bool bolp = pos.bufpos == BEGV || FETCH_BYTE (pos.bytepos - 1) == '\n';
if (pos.bufpos < ZV)
{
set_marker_restricted_both (w->start, w->contents,
pos.bufpos, pos.bytepos);
w->start_at_line_beg = bolp;
wset_update_mode_line (w);
/* Set force_start so that redisplay_window will run
the window-scroll-functions. */
w->force_start = true;
SET_PT_BOTH (pos.bufpos, pos.bytepos);
if (n > 0)
pos = *vmotion (PT, PT_BYTE, ht / 2, w);
else if (n < 0)
pos = *vmotion (PT, PT_BYTE, - (ht / 2), w);
SET_PT_BOTH (pos.bufpos, pos.bytepos);
}
else
{
if (noerror)
return;
else
xsignal0 (Qend_of_buffer);
}
}
/* Implementation of window_scroll that works based on pixel line
heights. See the comment of window_scroll for parameter
descriptions. */

View file

@ -20165,7 +20165,20 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
from point. */
centering_position = window_box_height (w) / 2;
}
move_it_vertically_backward (&it, centering_position);
if (current_buffer->long_line_optimizations_p
&& it.line_wrap == TRUNCATE)
{
/* For very long and truncated lines, go back using a simplified
method, which ignored any inaccuracies due to line-height
differences, display properties/overlays, etc. */
int nlines = centering_position / frame_line_height;
while (nlines-- && IT_CHARPOS (it) > BEGV)
back_to_previous_visible_line_start (&it);
reseat_1 (&it, it.current.pos, true);
}
else
move_it_vertically_backward (&it, centering_position);
eassert (IT_CHARPOS (it) >= BEGV);