diff options
author | Dmitry Gutov <dgutov@yandex.ru> | 2022-08-15 02:22:59 +0300 |
---|---|---|
committer | Dmitry Gutov <dgutov@yandex.ru> | 2022-08-15 02:22:59 +0300 |
commit | ee3a674c7c9e39fe7ff296ce1f9830fc45520de8 (patch) | |
tree | e8ba1e7be54314f208454e80e3d31044c913f3eb /src/xdisp.c | |
parent | fe0e53d963899a16e0dd1bbc1ba10a6b59f7989e (diff) | |
parent | 0a8e88fd83db5398d36064a7f87cff5b57da7284 (diff) | |
download | emacs-scratch/font_lock_large_files.tar.gz |
Merge branch 'master' into scratch/font_lock_large_filesscratch/font_lock_large_files
Diffstat (limited to 'src/xdisp.c')
-rw-r--r-- | src/xdisp.c | 203 |
1 files changed, 155 insertions, 48 deletions
diff --git a/src/xdisp.c b/src/xdisp.c index 1fcff2c2e3b..1e8f70b2db9 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11040,6 +11040,15 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) int partial_line_height (struct it *it_origin) { + /* In a buffer with very long and truncated lines, we ignore the + possibly-partial height of the last line in the window: it is too + expensive to compute that (since in most cases that involves + going all the way to ZV), and the effect of ignoring it is + relatively minor. */ + if (XBUFFER (it_origin->w->contents)->long_line_optimizations_p + && it_origin->line_wrap == TRUNCATE) + return 0; + int partial_height; void *it_data = NULL; struct it it; @@ -11063,6 +11072,51 @@ partial_line_height (struct it *it_origin) return partial_height; } +/* Approximate move_it_in_display_line_to for very long and truncated + display lines, when moving horizontally. This is used when the + buffer's long_line_optimizations_p flag is set. It ignores various + complications, like different font sizes, invisible text, display + and overlay strings, and, to some degree, bidirectional text. So + caveat emptor! + + Starting from IT's position, reseat IT after skipping NCHARS + characters or to the next newline/ZV, whichever comes first. Return + what move_it_in_display_line_to would have returned in this case. */ + +static enum move_it_result +fast_move_it_horizontally (struct it *it, ptrdiff_t nchars) +{ + ptrdiff_t nl_bytepos; + ptrdiff_t nl_pos = find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it), + 1, &nl_bytepos); + struct text_pos new_pos; + enum move_it_result move_result; + + if (nl_pos - IT_CHARPOS (*it) > nchars) + { + SET_TEXT_POS (new_pos, + IT_CHARPOS (*it) + nchars, + CHAR_TO_BYTE (IT_CHARPOS (*it) + nchars)); + move_result = MOVE_X_REACHED; + } + else + { + if (nl_bytepos < ZV_BYTE + || (nl_bytepos > BEGV_BYTE + && FETCH_BYTE (nl_bytepos - 1) == '\n')) + { + nl_pos--; + nl_bytepos--; + move_result = MOVE_NEWLINE_OR_CR; + } + else + move_result = MOVE_POS_MATCH_OR_ZV; + SET_TEXT_POS (new_pos, nl_pos, nl_bytepos); + } + reseat (it, new_pos, false); + return move_result; +} + /* Return true if IT points into the middle of a display vector. */ bool @@ -13106,8 +13160,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 @@ -15776,7 +15829,20 @@ hscroll_window_tree (Lisp_Object window) it.first_visible_x = window_hscroll_limited (w, it.f) * FRAME_COLUMN_WIDTH (it.f); it.last_visible_x = DISP_INFINITY; - move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); + + ptrdiff_t nchars = pt - IT_CHARPOS (it); + if (current_buffer->long_line_optimizations_p + && nchars > large_hscroll_threshold) + { + /* Special optimization for very long and truncated + lines which need to be hscrolled far to the left: + jump directly to the (approximate) first position + that is visible, instead of slowly walking there. */ + fast_move_it_horizontally (&it, nchars); + it.current_x += nchars * FRAME_COLUMN_WIDTH (it.f); + } + else + move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); /* If the line ends in an overlay string with a newline, we might infloop, because displaying the window will want to put the cursor after the overlay, i.e. at X @@ -15789,7 +15855,14 @@ hscroll_window_tree (Lisp_Object window) if (hscl) it.first_visible_x = (window_hscroll_limited (w, it.f) * FRAME_COLUMN_WIDTH (it.f)); - move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); + if (current_buffer->long_line_optimizations_p + && nchars > large_hscroll_threshold) + { + fast_move_it_horizontally (&it, nchars - 1); + it.current_x += (nchars - 1) * FRAME_COLUMN_WIDTH (it.f); + } + else + move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); } current_buffer = saved_current_buffer; @@ -16727,9 +16800,23 @@ redisplay_internal (void) it.current_y = this_line_y; it.vpos = this_line_vpos; - /* The call to move_it_to stops in front of PT, but - moves over before-strings. */ - move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + if (current_buffer->long_line_optimizations_p + && it.line_wrap == TRUNCATE + && PT - CHARPOS (tlbufpos) > large_hscroll_threshold) + { + /* When lines are very long and truncated, jumping to + the next visible line is much faster than slowly + iterating there. */ + reseat_at_next_visible_line_start (&it, false); + if (IT_CHARPOS (it) <= PT) /* point moved off this line */ + it.vpos = this_line_vpos + 1; + } + else + { + /* The call to move_it_to stops in front of PT, but + moves over before-strings. */ + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + } if (it.vpos == this_line_vpos && (row = MATRIX_ROW (w->current_matrix, this_line_vpos), @@ -18119,8 +18206,8 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp) { specpdl_ref count = SPECPDL_INDEX (); specbind (Qinhibit_quit, Qt); - run_hook_with_args_2 (Qwindow_scroll_functions, window, - make_fixnum (CHARPOS (startp))); + safe_run_hooks_2 + (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp))); unbind_to (count, Qnil); SET_TEXT_POS_FROM_MARKER (startp, w->start); /* In case the hook functions switch buffers. */ @@ -19229,6 +19316,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. @@ -19504,33 +19601,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 + } } } @@ -20256,7 +20356,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) @@ -24496,8 +24595,26 @@ display_line (struct it *it, int cursor_vpos) it->first_visible_x += x_incr; it->last_visible_x += x_incr; } - move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x, - MOVE_TO_POS | MOVE_TO_X); + if (current_buffer->long_line_optimizations_p + && it->line_wrap == TRUNCATE + && window_hscroll_limited (it->w, it->f) > large_hscroll_threshold) + { + /* Special optimization for very long and truncated lines + which are hscrolled far to the left: jump directly to the + (approximate) position that is visible, instead of slowly + walking there. */ + ptrdiff_t chars_to_skip = + it->first_visible_x / FRAME_COLUMN_WIDTH (it->f); + move_result = fast_move_it_horizontally (it, chars_to_skip); + + if (move_result == MOVE_X_REACHED) + it->current_x = it->first_visible_x; + else /* use arbitrary value < first_visible_x */ + it->current_x = it->first_visible_x - FRAME_COLUMN_WIDTH (it->f); + } + else + move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x, + MOVE_TO_POS | MOVE_TO_X); /* If we are under a large hscroll, move_it_in_display_line_to could hit the end of the line without reaching first_visible_x. Pretend that we did reach it. This is @@ -27758,17 +27875,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 (); @@ -36112,6 +36218,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"); |