[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master a71c05b44d: Further speedups of redisplay of long and truncated l
From: |
Eli Zaretskii |
Subject: |
master a71c05b44d: Further speedups of redisplay of long and truncated lines |
Date: |
Sun, 14 Aug 2022 08:50:27 -0400 (EDT) |
branch: master
commit a71c05b44de74fe16691f680df34c4534992e472
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>
Further speedups of redisplay of long and truncated lines
* src/xdisp.c (mode_line_update_needed, redisplay_window)
(decode_mode_spec): Don't avoid calling current_column, as it is
now fast enough.
(redisplay_window) <optional_new_start>: Don't call 'move_it_to'
if its result will not be used.
(Flong_line_optimizations_p): New primitive.
* src/indent.c (Fcurrent_column): Doc fix.
(current_column, scan_for_column): When in a buffer with long
and/or truncated lines, quickly return an approximate value.
* src/window.c (Frecenter): Use the old text-mode code when the
buffer has very long lines.
* lisp/simple.el (line-move): Avoid costly calls to
'line-move-partial' and 'line-move-visual' when lines are
truncated and/or very long.
(move-beginning-of-line): Call 'line-beginning-position' instead
of the slower 'skip-chars-backward'.
* etc/NEWS: Announce 'long-line-optimizations-p'.
---
etc/NEWS | 3 +++
lisp/simple.el | 31 ++++++++++++++++++++---
src/indent.c | 60 ++++++++++++++++++++++++++++++++++++++------
src/window.c | 9 ++++---
src/xdisp.c | 79 +++++++++++++++++++++++++++++-----------------------------
5 files changed, 129 insertions(+), 53 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index 2b942f67b0..8fc3df63eb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -400,6 +400,9 @@ and the major mode with 'M-x so-long-mode', or visit the
file with
Note that the display optimizations in these cases may cause the
buffer to be occasionally mis-fontified.
+The new function 'long-line-optimizations-p' returns non-nil when
+these optimizations are in effect in the current buffer.
+
+++
** New command to change the font size globally.
To increase the font size, type 'C-x C-M-+' or 'C-x C-M-='; to
diff --git a/lisp/simple.el b/lisp/simple.el
index ce3895176e..1e6e5e11e0 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -7692,11 +7692,33 @@ not vscroll."
;; But don't vscroll in a keyboard macro.
(not defining-kbd-macro)
(not executing-kbd-macro)
+ ;; Lines are not truncated...
+ (not
+ (and
+ (or truncate-lines
+ (and (integerp truncate-partial-width-windows)
+ (< (window-total-width)
+ truncate-partial-width-windows))
+ (and truncate-partial-width-windows
+ (not (integerp truncate-partial-width-windows))
+ (not (window-full-width-p))))
+ ;; ...or if lines are truncated, this buffer
+ ;; doesn't have very long lines.
+ (long-line-optimizations-p)))
(line-move-partial arg noerror))
(set-window-vscroll nil 0 t)
(if (and line-move-visual
;; Display-based column are incompatible with goal-column.
(not goal-column)
+ ;; Lines aren't truncated.
+ (not
+ (or truncate-lines
+ (and (integerp truncate-partial-width-windows)
+ (< (window-width)
+ truncate-partial-width-windows))
+ (and truncate-partial-width-windows
+ (not (integerp truncate-partial-width-windows))
+ (not (window-full-width-p)))))
;; When the text in the window is scrolled to the left,
;; display-based motion doesn't make sense (because each
;; logical line occupies exactly one screen line).
@@ -8133,10 +8155,11 @@ For motion by visual lines, see
`beginning-of-visual-line'."
(line-move (1- arg) t)))
;; Move to beginning-of-line, ignoring fields and invisible text.
- (skip-chars-backward "^\n")
- (while (and (not (bobp)) (invisible-p (1- (point))))
- (goto-char (previous-char-property-change (point)))
- (skip-chars-backward "^\n"))
+ (let ((inhibit-field-text-motion t))
+ (goto-char (line-beginning-position))
+ (while (and (not (bobp)) (invisible-p (1- (point))))
+ (goto-char (previous-char-property-change (point)))
+ (goto-char (line-beginning-position))))
;; Now find first visible char in the line.
(while (and (< (point) orig) (invisible-p (point)))
diff --git a/src/indent.c b/src/indent.c
index d2dfaee254..cb368024d9 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -306,8 +306,8 @@ and point (e.g., control characters will have a width of 2
or 4, tabs
will have a variable width).
Ignores finite width of frame, which means that this function may return
values greater than (frame-width).
-In a buffer with very long lines, the value can be zero, because calculating
-the exact number is very expensive.
+In a buffer with very long lines, the value will be an approximation,
+because calculating the exact number is very expensive.
Whether the line is visible (if `selective-display' is t) has no effect;
however, ^M is treated as end of line when `selective-display' is t.
Text that has an invisible property is considered as having width 0, unless
@@ -316,8 +316,6 @@ Text that has an invisible property is considered as having
width 0, unless
{
Lisp_Object temp;
- if (current_buffer->long_line_optimizations_p)
- return make_fixnum (0);
XSETFASTINT (temp, current_column ());
return temp;
}
@@ -346,6 +344,14 @@ current_column (void)
&& MODIFF == last_known_column_modified)
return last_known_column;
+ ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
+ NULL, NULL, 1);
+
+ /* Avoid becoming abysmally slow for very long lines. */
+ if (current_buffer->long_line_optimizations_p
+ && !NILP (Vlong_line_threshold)
+ && PT - line_beg > XFIXNUM (Vlong_line_threshold))
+ return PT - line_beg; /* this is an approximation! */
/* If the buffer has overlays, text properties,
or multibyte characters, use a more general algorithm. */
if (buffer_intervals (current_buffer)
@@ -561,13 +567,53 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
- next_boundary = scan;
- prev_pos = scan;
- prev_bpos = scan_byte;
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
w = ! NILP (window) ? XWINDOW (window) : NULL;
+ if (current_buffer->long_line_optimizations_p)
+ {
+ bool lines_truncated = false;
+
+ if (!NILP (BVAR (current_buffer, truncate_lines)))
+ lines_truncated = true;
+ else if (w && FIXNUMP (Vtruncate_partial_width_windows))
+ lines_truncated =
+ w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
+ else if (w && !NILP (Vtruncate_partial_width_windows))
+ lines_truncated =
+ w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w)));
+ /* Special optimization for buffers with long and truncated
+ lines: assumes that each character is a single column. */
+ if (lines_truncated)
+ {
+ ptrdiff_t bolpos = scan;
+ /* The newline which ends this line or ZV. */
+ ptrdiff_t eolpos =
+ find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
+
+ scan = bolpos + goal;
+ if (scan > end)
+ scan = end;
+ if (scan > eolpos)
+ scan = (eolpos == ZV ? ZV : eolpos - 1);
+ col = scan - bolpos;
+ if (col > large_hscroll_threshold)
+ {
+ prev_col = col - 1;
+ prev_pos = scan - 1;
+ prev_bpos = CHAR_TO_BYTE (scan);
+ goto endloop;
+ }
+ /* Restore the values we've overwritten above. */
+ scan = bolpos;
+ col = 0;
+ }
+ }
+ next_boundary = scan;
+ prev_pos = scan;
+ prev_bpos = scan_byte;
+
memset (&cmp_it, 0, sizeof cmp_it);
cmp_it.id = -1;
composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
diff --git a/src/window.c b/src/window.c
index afb8f75537..c8fcb3a607 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6575,9 +6575,12 @@ and redisplay normally--don't erase and redraw the
frame. */)
in case scroll_margin is buffer-local. */
this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES);
- /* Don't use redisplay code for initial frames, as the necessary
- data structures might not be set up yet then. */
- if (!FRAME_INITIAL_P (XFRAME (w->frame)))
+ /* Don't use the display code for initial frames, as the necessary
+ data structures might not be set up yet then. Also don't use it
+ for buffers with very long lines, as it tremdously slows down
+ redisplay, especially when lines are truncated. */
+ if (!FRAME_INITIAL_P (XFRAME (w->frame))
+ && !current_buffer->long_line_optimizations_p)
{
specpdl_ref count = SPECPDL_INDEX ();
diff --git a/src/xdisp.c b/src/xdisp.c
index 7ee42918eb..0248e8e53f 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -13174,8 +13174,7 @@ mode_line_update_needed (struct window *w)
{
return (w->column_number_displayed != -1
&& !(PT == w->last_point && !window_outdated (w))
- && (!current_buffer->long_line_optimizations_p
- && w->column_number_displayed != current_column ()));
+ && (w->column_number_displayed != current_column ()));
}
/* True if window start of W is frozen and may not be changed during
@@ -19331,6 +19330,16 @@ window_start_acceptable_p (Lisp_Object window,
ptrdiff_t startp)
return true;
}
+DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p,
Slong_line_optimizations_p,
+ 0, 0, 0,
+ doc: /* Return non-nil if long-line optimizations are in effect in
current buffer.
+See `long-line-threshold' and `large-hscroll-threshold' for what these
+optimizations mean and when they are in effect. */)
+ (void)
+{
+ return current_buffer->long_line_optimizations_p ? Qt : Qnil;
+}
+
/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only
selected_window is redisplayed.
@@ -19606,33 +19615,36 @@ redisplay_window (Lisp_Object window, bool
just_this_one_p)
ptrdiff_t it_charpos;
w->optional_new_start = false;
- start_display (&it, w, startp);
- move_it_to (&it, PT, 0, it.last_visible_y, -1,
- MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
- /* Record IT's position now, since line_bottom_y might change
- that. */
- it_charpos = IT_CHARPOS (it);
- /* Make sure we set the force_start flag only if the cursor row
- will be fully visible. Otherwise, the code under force_start
- label below will try to move point back into view, which is
- not what the code which sets optional_new_start wants. */
- if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
- && !w->force_start)
- {
- if (it_charpos == PT)
- w->force_start = true;
- /* IT may overshoot PT if text at PT is invisible. */
- else if (it_charpos > PT && CHARPOS (startp) <= PT)
- w->force_start = true;
+ if (!w->force_start)
+ {
+ start_display (&it, w, startp);
+ move_it_to (&it, PT, 0, it.last_visible_y, -1,
+ MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ /* Record IT's position now, since line_bottom_y might
+ change that. */
+ it_charpos = IT_CHARPOS (it);
+ /* Make sure we set the force_start flag only if the cursor
+ row will be fully visible. Otherwise, the code under
+ force_start label below will try to move point back into
+ view, which is not what the code which sets
+ optional_new_start wants. */
+ if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
+ {
+ if (it_charpos == PT)
+ w->force_start = true;
+ /* IT may overshoot PT if text at PT is invisible. */
+ else if (it_charpos > PT && CHARPOS (startp) <= PT)
+ w->force_start = true;
#ifdef GLYPH_DEBUG
- if (w->force_start)
- {
- if (window_frozen_p (w))
- debug_method_add (w, "set force_start from frozen window
start");
- else
- debug_method_add (w, "set force_start from optional_new_start");
- }
+ if (w->force_start)
+ {
+ if (window_frozen_p (w))
+ debug_method_add (w, "set force_start from frozen window
start");
+ else
+ debug_method_add (w, "set force_start from
optional_new_start");
+ }
#endif
+ }
}
}
@@ -20358,7 +20370,6 @@ redisplay_window (Lisp_Object window, bool
just_this_one_p)
|| w->base_line_pos > 0
/* Column number is displayed and different from the one displayed. */
|| (w->column_number_displayed != -1
- && !current_buffer->long_line_optimizations_p
&& (w->column_number_displayed != current_column ())))
/* This means that the window has a mode line. */
&& (window_wants_mode_line (w)
@@ -27878,17 +27889,6 @@ decode_mode_spec (struct window *w, register int c,
int field_width,
even crash emacs.) */
if (mode_line_target == MODE_LINE_TITLE)
return "";
- else if (b->long_line_optimizations_p)
- {
- char *p = decode_mode_spec_buf;
- int pad = width - 2;
- while (pad-- > 0)
- *p++ = ' ';
- *p++ = '?';
- *p++ = '?';
- *p = '\0';
- return decode_mode_spec_buf;
- }
else
{
ptrdiff_t col = current_column ();
@@ -36232,6 +36232,7 @@ be let-bound around code that needs to disable messages
temporarily. */);
defsubr (&Sbidi_find_overridden_directionality);
defsubr (&Sdisplay__line_is_continued_p);
defsubr (&Sget_display_property);
+ defsubr (&Slong_line_optimizations_p);
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master a71c05b44d: Further speedups of redisplay of long and truncated lines,
Eli Zaretskii <=