aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2022-08-14 15:47:59 +0300
committerEli Zaretskii2022-08-14 15:49:37 +0300
commita71c05b44de74fe16691f680df34c4534992e472 (patch)
tree0fdd2a19ea5297f83d2be1b8e609599572923200 /src
parentb93e14fa0fd5833adbdd88ec86fccc4b59172302 (diff)
downloademacs-a71c05b44de74fe16691f680df34c4534992e472.tar.gz
emacs-a71c05b44de74fe16691f680df34c4534992e472.zip
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'.
Diffstat (limited to 'src')
-rw-r--r--src/indent.c60
-rw-r--r--src/window.c9
-rw-r--r--src/xdisp.c79
3 files changed, 99 insertions, 49 deletions
diff --git a/src/indent.c b/src/indent.c
index d2dfaee254e..cb368024d97 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
306will have a variable width). 306will have a variable width).
307Ignores finite width of frame, which means that this function may return 307Ignores finite width of frame, which means that this function may return
308values greater than (frame-width). 308values greater than (frame-width).
309In a buffer with very long lines, the value can be zero, because calculating 309In a buffer with very long lines, the value will be an approximation,
310the exact number is very expensive. 310because calculating the exact number is very expensive.
311Whether the line is visible (if `selective-display' is t) has no effect; 311Whether the line is visible (if `selective-display' is t) has no effect;
312however, ^M is treated as end of line when `selective-display' is t. 312however, ^M is treated as end of line when `selective-display' is t.
313Text that has an invisible property is considered as having width 0, unless 313Text 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
316{ 316{
317 Lisp_Object temp; 317 Lisp_Object temp;
318 318
319 if (current_buffer->long_line_optimizations_p)
320 return make_fixnum (0);
321 XSETFASTINT (temp, current_column ()); 319 XSETFASTINT (temp, current_column ());
322 return temp; 320 return temp;
323} 321}
@@ -346,6 +344,14 @@ current_column (void)
346 && MODIFF == last_known_column_modified) 344 && MODIFF == last_known_column_modified)
347 return last_known_column; 345 return last_known_column;
348 346
347 ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
348 NULL, NULL, 1);
349
350 /* Avoid becoming abysmally slow for very long lines. */
351 if (current_buffer->long_line_optimizations_p
352 && !NILP (Vlong_line_threshold)
353 && PT - line_beg > XFIXNUM (Vlong_line_threshold))
354 return PT - line_beg; /* this is an approximation! */
349 /* If the buffer has overlays, text properties, 355 /* If the buffer has overlays, text properties,
350 or multibyte characters, use a more general algorithm. */ 356 or multibyte characters, use a more general algorithm. */
351 if (buffer_intervals (current_buffer) 357 if (buffer_intervals (current_buffer)
@@ -561,13 +567,53 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
561 ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos; 567 ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
562 568
563 scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1); 569 scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
564 next_boundary = scan;
565 prev_pos = scan;
566 prev_bpos = scan_byte;
567 570
568 window = Fget_buffer_window (Fcurrent_buffer (), Qnil); 571 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
569 w = ! NILP (window) ? XWINDOW (window) : NULL; 572 w = ! NILP (window) ? XWINDOW (window) : NULL;
570 573
574 if (current_buffer->long_line_optimizations_p)
575 {
576 bool lines_truncated = false;
577
578 if (!NILP (BVAR (current_buffer, truncate_lines)))
579 lines_truncated = true;
580 else if (w && FIXNUMP (Vtruncate_partial_width_windows))
581 lines_truncated =
582 w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
583 else if (w && !NILP (Vtruncate_partial_width_windows))
584 lines_truncated =
585 w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w)));
586 /* Special optimization for buffers with long and truncated
587 lines: assumes that each character is a single column. */
588 if (lines_truncated)
589 {
590 ptrdiff_t bolpos = scan;
591 /* The newline which ends this line or ZV. */
592 ptrdiff_t eolpos =
593 find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
594
595 scan = bolpos + goal;
596 if (scan > end)
597 scan = end;
598 if (scan > eolpos)
599 scan = (eolpos == ZV ? ZV : eolpos - 1);
600 col = scan - bolpos;
601 if (col > large_hscroll_threshold)
602 {
603 prev_col = col - 1;
604 prev_pos = scan - 1;
605 prev_bpos = CHAR_TO_BYTE (scan);
606 goto endloop;
607 }
608 /* Restore the values we've overwritten above. */
609 scan = bolpos;
610 col = 0;
611 }
612 }
613 next_boundary = scan;
614 prev_pos = scan;
615 prev_bpos = scan_byte;
616
571 memset (&cmp_it, 0, sizeof cmp_it); 617 memset (&cmp_it, 0, sizeof cmp_it);
572 cmp_it.id = -1; 618 cmp_it.id = -1;
573 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil); 619 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
diff --git a/src/window.c b/src/window.c
index afb8f75537b..c8fcb3a607f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6575,9 +6575,12 @@ and redisplay normally--don't erase and redraw the frame. */)
6575 in case scroll_margin is buffer-local. */ 6575 in case scroll_margin is buffer-local. */
6576 this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES); 6576 this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES);
6577 6577
6578 /* Don't use redisplay code for initial frames, as the necessary 6578 /* Don't use the display code for initial frames, as the necessary
6579 data structures might not be set up yet then. */ 6579 data structures might not be set up yet then. Also don't use it
6580 if (!FRAME_INITIAL_P (XFRAME (w->frame))) 6580 for buffers with very long lines, as it tremdously slows down
6581 redisplay, especially when lines are truncated. */
6582 if (!FRAME_INITIAL_P (XFRAME (w->frame))
6583 && !current_buffer->long_line_optimizations_p)
6581 { 6584 {
6582 specpdl_ref count = SPECPDL_INDEX (); 6585 specpdl_ref count = SPECPDL_INDEX ();
6583 6586
diff --git a/src/xdisp.c b/src/xdisp.c
index 7ee42918eb6..0248e8e53f1 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -13174,8 +13174,7 @@ mode_line_update_needed (struct window *w)
13174{ 13174{
13175 return (w->column_number_displayed != -1 13175 return (w->column_number_displayed != -1
13176 && !(PT == w->last_point && !window_outdated (w)) 13176 && !(PT == w->last_point && !window_outdated (w))
13177 && (!current_buffer->long_line_optimizations_p 13177 && (w->column_number_displayed != current_column ()));
13178 && w->column_number_displayed != current_column ()));
13179} 13178}
13180 13179
13181/* True if window start of W is frozen and may not be changed during 13180/* 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)
19331 return true; 19330 return true;
19332} 19331}
19333 19332
19333DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p, Slong_line_optimizations_p,
19334 0, 0, 0,
19335 doc: /* Return non-nil if long-line optimizations are in effect in current buffer.
19336See `long-line-threshold' and `large-hscroll-threshold' for what these
19337optimizations mean and when they are in effect. */)
19338 (void)
19339{
19340 return current_buffer->long_line_optimizations_p ? Qt : Qnil;
19341}
19342
19334/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only 19343/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only
19335 selected_window is redisplayed. 19344 selected_window is redisplayed.
19336 19345
@@ -19606,33 +19615,36 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19606 ptrdiff_t it_charpos; 19615 ptrdiff_t it_charpos;
19607 19616
19608 w->optional_new_start = false; 19617 w->optional_new_start = false;
19609 start_display (&it, w, startp); 19618 if (!w->force_start)
19610 move_it_to (&it, PT, 0, it.last_visible_y, -1, 19619 {
19611 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); 19620 start_display (&it, w, startp);
19612 /* Record IT's position now, since line_bottom_y might change 19621 move_it_to (&it, PT, 0, it.last_visible_y, -1,
19613 that. */ 19622 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
19614 it_charpos = IT_CHARPOS (it); 19623 /* Record IT's position now, since line_bottom_y might
19615 /* Make sure we set the force_start flag only if the cursor row 19624 change that. */
19616 will be fully visible. Otherwise, the code under force_start 19625 it_charpos = IT_CHARPOS (it);
19617 label below will try to move point back into view, which is 19626 /* Make sure we set the force_start flag only if the cursor
19618 not what the code which sets optional_new_start wants. */ 19627 row will be fully visible. Otherwise, the code under
19619 if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y) 19628 force_start label below will try to move point back into
19620 && !w->force_start) 19629 view, which is not what the code which sets
19621 { 19630 optional_new_start wants. */
19622 if (it_charpos == PT) 19631 if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
19623 w->force_start = true; 19632 {
19624 /* IT may overshoot PT if text at PT is invisible. */ 19633 if (it_charpos == PT)
19625 else if (it_charpos > PT && CHARPOS (startp) <= PT) 19634 w->force_start = true;
19626 w->force_start = true; 19635 /* IT may overshoot PT if text at PT is invisible. */
19636 else if (it_charpos > PT && CHARPOS (startp) <= PT)
19637 w->force_start = true;
19627#ifdef GLYPH_DEBUG 19638#ifdef GLYPH_DEBUG
19628 if (w->force_start) 19639 if (w->force_start)
19629 { 19640 {
19630 if (window_frozen_p (w)) 19641 if (window_frozen_p (w))
19631 debug_method_add (w, "set force_start from frozen window start"); 19642 debug_method_add (w, "set force_start from frozen window start");
19632 else 19643 else
19633 debug_method_add (w, "set force_start from optional_new_start"); 19644 debug_method_add (w, "set force_start from optional_new_start");
19634 } 19645 }
19635#endif 19646#endif
19647 }
19636 } 19648 }
19637 } 19649 }
19638 19650
@@ -20358,7 +20370,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
20358 || w->base_line_pos > 0 20370 || w->base_line_pos > 0
20359 /* Column number is displayed and different from the one displayed. */ 20371 /* Column number is displayed and different from the one displayed. */
20360 || (w->column_number_displayed != -1 20372 || (w->column_number_displayed != -1
20361 && !current_buffer->long_line_optimizations_p
20362 && (w->column_number_displayed != current_column ()))) 20373 && (w->column_number_displayed != current_column ())))
20363 /* This means that the window has a mode line. */ 20374 /* This means that the window has a mode line. */
20364 && (window_wants_mode_line (w) 20375 && (window_wants_mode_line (w)
@@ -27878,17 +27889,6 @@ decode_mode_spec (struct window *w, register int c, int field_width,
27878 even crash emacs.) */ 27889 even crash emacs.) */
27879 if (mode_line_target == MODE_LINE_TITLE) 27890 if (mode_line_target == MODE_LINE_TITLE)
27880 return ""; 27891 return "";
27881 else if (b->long_line_optimizations_p)
27882 {
27883 char *p = decode_mode_spec_buf;
27884 int pad = width - 2;
27885 while (pad-- > 0)
27886 *p++ = ' ';
27887 *p++ = '?';
27888 *p++ = '?';
27889 *p = '\0';
27890 return decode_mode_spec_buf;
27891 }
27892 else 27892 else
27893 { 27893 {
27894 ptrdiff_t col = current_column (); 27894 ptrdiff_t col = current_column ();
@@ -36232,6 +36232,7 @@ be let-bound around code that needs to disable messages temporarily. */);
36232 defsubr (&Sbidi_find_overridden_directionality); 36232 defsubr (&Sbidi_find_overridden_directionality);
36233 defsubr (&Sdisplay__line_is_continued_p); 36233 defsubr (&Sdisplay__line_is_continued_p);
36234 defsubr (&Sget_display_property); 36234 defsubr (&Sget_display_property);
36235 defsubr (&Slong_line_optimizations_p);
36235 36236
36236 DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); 36237 DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
36237 DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); 36238 DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");