diff options
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) | |||
| 11040 | int | 11040 | int |
| 11041 | partial_line_height (struct it *it_origin) | 11041 | partial_line_height (struct it *it_origin) |
| 11042 | { | 11042 | { |
| 11043 | /* In a buffer with very long and truncated lines, we ignore the | ||
| 11044 | possibly-partial height of the last line in the window: it is too | ||
| 11045 | expensive to compute that (since in most cases that involves | ||
| 11046 | going all the way to ZV), and the effect of ignoring it is | ||
| 11047 | relatively minor. */ | ||
| 11048 | if (XBUFFER (it_origin->w->contents)->long_line_optimizations_p | ||
| 11049 | && it_origin->line_wrap == TRUNCATE) | ||
| 11050 | return 0; | ||
| 11051 | |||
| 11043 | int partial_height; | 11052 | int partial_height; |
| 11044 | void *it_data = NULL; | 11053 | void *it_data = NULL; |
| 11045 | struct it it; | 11054 | struct it it; |
| @@ -11063,6 +11072,51 @@ partial_line_height (struct it *it_origin) | |||
| 11063 | return partial_height; | 11072 | return partial_height; |
| 11064 | } | 11073 | } |
| 11065 | 11074 | ||
| 11075 | /* Approximate move_it_in_display_line_to for very long and truncated | ||
| 11076 | display lines, when moving horizontally. This is used when the | ||
| 11077 | buffer's long_line_optimizations_p flag is set. It ignores various | ||
| 11078 | complications, like different font sizes, invisible text, display | ||
| 11079 | and overlay strings, and, to some degree, bidirectional text. So | ||
| 11080 | caveat emptor! | ||
| 11081 | |||
| 11082 | Starting from IT's position, reseat IT after skipping NCHARS | ||
| 11083 | characters or to the next newline/ZV, whichever comes first. Return | ||
| 11084 | what move_it_in_display_line_to would have returned in this case. */ | ||
| 11085 | |||
| 11086 | static enum move_it_result | ||
| 11087 | fast_move_it_horizontally (struct it *it, ptrdiff_t nchars) | ||
| 11088 | { | ||
| 11089 | ptrdiff_t nl_bytepos; | ||
| 11090 | ptrdiff_t nl_pos = find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it), | ||
| 11091 | 1, &nl_bytepos); | ||
| 11092 | struct text_pos new_pos; | ||
| 11093 | enum move_it_result move_result; | ||
| 11094 | |||
| 11095 | if (nl_pos - IT_CHARPOS (*it) > nchars) | ||
| 11096 | { | ||
| 11097 | SET_TEXT_POS (new_pos, | ||
| 11098 | IT_CHARPOS (*it) + nchars, | ||
| 11099 | CHAR_TO_BYTE (IT_CHARPOS (*it) + nchars)); | ||
| 11100 | move_result = MOVE_X_REACHED; | ||
| 11101 | } | ||
| 11102 | else | ||
| 11103 | { | ||
| 11104 | if (nl_bytepos < ZV_BYTE | ||
| 11105 | || (nl_bytepos > BEGV_BYTE | ||
| 11106 | && FETCH_BYTE (nl_bytepos - 1) == '\n')) | ||
| 11107 | { | ||
| 11108 | nl_pos--; | ||
| 11109 | nl_bytepos--; | ||
| 11110 | move_result = MOVE_NEWLINE_OR_CR; | ||
| 11111 | } | ||
| 11112 | else | ||
| 11113 | move_result = MOVE_POS_MATCH_OR_ZV; | ||
| 11114 | SET_TEXT_POS (new_pos, nl_pos, nl_bytepos); | ||
| 11115 | } | ||
| 11116 | reseat (it, new_pos, false); | ||
| 11117 | return move_result; | ||
| 11118 | } | ||
| 11119 | |||
| 11066 | /* Return true if IT points into the middle of a display vector. */ | 11120 | /* Return true if IT points into the middle of a display vector. */ |
| 11067 | 11121 | ||
| 11068 | bool | 11122 | bool |
| @@ -13106,8 +13160,7 @@ mode_line_update_needed (struct window *w) | |||
| 13106 | { | 13160 | { |
| 13107 | return (w->column_number_displayed != -1 | 13161 | return (w->column_number_displayed != -1 |
| 13108 | && !(PT == w->last_point && !window_outdated (w)) | 13162 | && !(PT == w->last_point && !window_outdated (w)) |
| 13109 | && (!current_buffer->long_line_optimizations_p | 13163 | && (w->column_number_displayed != current_column ())); |
| 13110 | && w->column_number_displayed != current_column ())); | ||
| 13111 | } | 13164 | } |
| 13112 | 13165 | ||
| 13113 | /* True if window start of W is frozen and may not be changed during | 13166 | /* True if window start of W is frozen and may not be changed during |
| @@ -15776,7 +15829,20 @@ hscroll_window_tree (Lisp_Object window) | |||
| 15776 | it.first_visible_x = window_hscroll_limited (w, it.f) | 15829 | it.first_visible_x = window_hscroll_limited (w, it.f) |
| 15777 | * FRAME_COLUMN_WIDTH (it.f); | 15830 | * FRAME_COLUMN_WIDTH (it.f); |
| 15778 | it.last_visible_x = DISP_INFINITY; | 15831 | it.last_visible_x = DISP_INFINITY; |
| 15779 | move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); | 15832 | |
| 15833 | ptrdiff_t nchars = pt - IT_CHARPOS (it); | ||
| 15834 | if (current_buffer->long_line_optimizations_p | ||
| 15835 | && nchars > large_hscroll_threshold) | ||
| 15836 | { | ||
| 15837 | /* Special optimization for very long and truncated | ||
| 15838 | lines which need to be hscrolled far to the left: | ||
| 15839 | jump directly to the (approximate) first position | ||
| 15840 | that is visible, instead of slowly walking there. */ | ||
| 15841 | fast_move_it_horizontally (&it, nchars); | ||
| 15842 | it.current_x += nchars * FRAME_COLUMN_WIDTH (it.f); | ||
| 15843 | } | ||
| 15844 | else | ||
| 15845 | move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); | ||
| 15780 | /* If the line ends in an overlay string with a newline, | 15846 | /* If the line ends in an overlay string with a newline, |
| 15781 | we might infloop, because displaying the window will | 15847 | we might infloop, because displaying the window will |
| 15782 | want to put the cursor after the overlay, i.e. at X | 15848 | want to put the cursor after the overlay, i.e. at X |
| @@ -15789,7 +15855,14 @@ hscroll_window_tree (Lisp_Object window) | |||
| 15789 | if (hscl) | 15855 | if (hscl) |
| 15790 | it.first_visible_x = (window_hscroll_limited (w, it.f) | 15856 | it.first_visible_x = (window_hscroll_limited (w, it.f) |
| 15791 | * FRAME_COLUMN_WIDTH (it.f)); | 15857 | * FRAME_COLUMN_WIDTH (it.f)); |
| 15792 | move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); | 15858 | if (current_buffer->long_line_optimizations_p |
| 15859 | && nchars > large_hscroll_threshold) | ||
| 15860 | { | ||
| 15861 | fast_move_it_horizontally (&it, nchars - 1); | ||
| 15862 | it.current_x += (nchars - 1) * FRAME_COLUMN_WIDTH (it.f); | ||
| 15863 | } | ||
| 15864 | else | ||
| 15865 | move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); | ||
| 15793 | } | 15866 | } |
| 15794 | current_buffer = saved_current_buffer; | 15867 | current_buffer = saved_current_buffer; |
| 15795 | 15868 | ||
| @@ -16727,9 +16800,23 @@ redisplay_internal (void) | |||
| 16727 | it.current_y = this_line_y; | 16800 | it.current_y = this_line_y; |
| 16728 | it.vpos = this_line_vpos; | 16801 | it.vpos = this_line_vpos; |
| 16729 | 16802 | ||
| 16730 | /* The call to move_it_to stops in front of PT, but | 16803 | if (current_buffer->long_line_optimizations_p |
| 16731 | moves over before-strings. */ | 16804 | && it.line_wrap == TRUNCATE |
| 16732 | move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); | 16805 | && PT - CHARPOS (tlbufpos) > large_hscroll_threshold) |
| 16806 | { | ||
| 16807 | /* When lines are very long and truncated, jumping to | ||
| 16808 | the next visible line is much faster than slowly | ||
| 16809 | iterating there. */ | ||
| 16810 | reseat_at_next_visible_line_start (&it, false); | ||
| 16811 | if (IT_CHARPOS (it) <= PT) /* point moved off this line */ | ||
| 16812 | it.vpos = this_line_vpos + 1; | ||
| 16813 | } | ||
| 16814 | else | ||
| 16815 | { | ||
| 16816 | /* The call to move_it_to stops in front of PT, but | ||
| 16817 | moves over before-strings. */ | ||
| 16818 | move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); | ||
| 16819 | } | ||
| 16733 | 16820 | ||
| 16734 | if (it.vpos == this_line_vpos | 16821 | if (it.vpos == this_line_vpos |
| 16735 | && (row = MATRIX_ROW (w->current_matrix, this_line_vpos), | 16822 | && (row = MATRIX_ROW (w->current_matrix, this_line_vpos), |
| @@ -18119,8 +18206,8 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp) | |||
| 18119 | { | 18206 | { |
| 18120 | specpdl_ref count = SPECPDL_INDEX (); | 18207 | specpdl_ref count = SPECPDL_INDEX (); |
| 18121 | specbind (Qinhibit_quit, Qt); | 18208 | specbind (Qinhibit_quit, Qt); |
| 18122 | run_hook_with_args_2 (Qwindow_scroll_functions, window, | 18209 | safe_run_hooks_2 |
| 18123 | make_fixnum (CHARPOS (startp))); | 18210 | (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp))); |
| 18124 | unbind_to (count, Qnil); | 18211 | unbind_to (count, Qnil); |
| 18125 | SET_TEXT_POS_FROM_MARKER (startp, w->start); | 18212 | SET_TEXT_POS_FROM_MARKER (startp, w->start); |
| 18126 | /* In case the hook functions switch buffers. */ | 18213 | /* In case the hook functions switch buffers. */ |
| @@ -19229,6 +19316,16 @@ window_start_acceptable_p (Lisp_Object window, ptrdiff_t startp) | |||
| 19229 | return true; | 19316 | return true; |
| 19230 | } | 19317 | } |
| 19231 | 19318 | ||
| 19319 | DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p, Slong_line_optimizations_p, | ||
| 19320 | 0, 0, 0, | ||
| 19321 | doc: /* Return non-nil if long-line optimizations are in effect in current buffer. | ||
| 19322 | See `long-line-threshold' and `large-hscroll-threshold' for what these | ||
| 19323 | optimizations mean and when they are in effect. */) | ||
| 19324 | (void) | ||
| 19325 | { | ||
| 19326 | return current_buffer->long_line_optimizations_p ? Qt : Qnil; | ||
| 19327 | } | ||
| 19328 | |||
| 19232 | /* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only | 19329 | /* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only |
| 19233 | selected_window is redisplayed. | 19330 | selected_window is redisplayed. |
| 19234 | 19331 | ||
| @@ -19504,33 +19601,36 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 19504 | ptrdiff_t it_charpos; | 19601 | ptrdiff_t it_charpos; |
| 19505 | 19602 | ||
| 19506 | w->optional_new_start = false; | 19603 | w->optional_new_start = false; |
| 19507 | start_display (&it, w, startp); | 19604 | if (!w->force_start) |
| 19508 | move_it_to (&it, PT, 0, it.last_visible_y, -1, | 19605 | { |
| 19509 | MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); | 19606 | start_display (&it, w, startp); |
| 19510 | /* Record IT's position now, since line_bottom_y might change | 19607 | move_it_to (&it, PT, 0, it.last_visible_y, -1, |
| 19511 | that. */ | 19608 | MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); |
| 19512 | it_charpos = IT_CHARPOS (it); | 19609 | /* Record IT's position now, since line_bottom_y might |
| 19513 | /* Make sure we set the force_start flag only if the cursor row | 19610 | change that. */ |
| 19514 | will be fully visible. Otherwise, the code under force_start | 19611 | it_charpos = IT_CHARPOS (it); |
| 19515 | label below will try to move point back into view, which is | 19612 | /* Make sure we set the force_start flag only if the cursor |
| 19516 | not what the code which sets optional_new_start wants. */ | 19613 | row will be fully visible. Otherwise, the code under |
| 19517 | if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y) | 19614 | force_start label below will try to move point back into |
| 19518 | && !w->force_start) | 19615 | view, which is not what the code which sets |
| 19519 | { | 19616 | optional_new_start wants. */ |
| 19520 | if (it_charpos == PT) | 19617 | if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y) |
| 19521 | w->force_start = true; | 19618 | { |
| 19522 | /* IT may overshoot PT if text at PT is invisible. */ | 19619 | if (it_charpos == PT) |
| 19523 | else if (it_charpos > PT && CHARPOS (startp) <= PT) | 19620 | w->force_start = true; |
| 19524 | w->force_start = true; | 19621 | /* IT may overshoot PT if text at PT is invisible. */ |
| 19622 | else if (it_charpos > PT && CHARPOS (startp) <= PT) | ||
| 19623 | w->force_start = true; | ||
| 19525 | #ifdef GLYPH_DEBUG | 19624 | #ifdef GLYPH_DEBUG |
| 19526 | if (w->force_start) | 19625 | if (w->force_start) |
| 19527 | { | 19626 | { |
| 19528 | if (window_frozen_p (w)) | 19627 | if (window_frozen_p (w)) |
| 19529 | debug_method_add (w, "set force_start from frozen window start"); | 19628 | debug_method_add (w, "set force_start from frozen window start"); |
| 19530 | else | 19629 | else |
| 19531 | debug_method_add (w, "set force_start from optional_new_start"); | 19630 | debug_method_add (w, "set force_start from optional_new_start"); |
| 19532 | } | 19631 | } |
| 19533 | #endif | 19632 | #endif |
| 19633 | } | ||
| 19534 | } | 19634 | } |
| 19535 | } | 19635 | } |
| 19536 | 19636 | ||
| @@ -20256,7 +20356,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 20256 | || w->base_line_pos > 0 | 20356 | || w->base_line_pos > 0 |
| 20257 | /* Column number is displayed and different from the one displayed. */ | 20357 | /* Column number is displayed and different from the one displayed. */ |
| 20258 | || (w->column_number_displayed != -1 | 20358 | || (w->column_number_displayed != -1 |
| 20259 | && !current_buffer->long_line_optimizations_p | ||
| 20260 | && (w->column_number_displayed != current_column ()))) | 20359 | && (w->column_number_displayed != current_column ()))) |
| 20261 | /* This means that the window has a mode line. */ | 20360 | /* This means that the window has a mode line. */ |
| 20262 | && (window_wants_mode_line (w) | 20361 | && (window_wants_mode_line (w) |
| @@ -24496,8 +24595,26 @@ display_line (struct it *it, int cursor_vpos) | |||
| 24496 | it->first_visible_x += x_incr; | 24595 | it->first_visible_x += x_incr; |
| 24497 | it->last_visible_x += x_incr; | 24596 | it->last_visible_x += x_incr; |
| 24498 | } | 24597 | } |
| 24499 | move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x, | 24598 | if (current_buffer->long_line_optimizations_p |
| 24500 | MOVE_TO_POS | MOVE_TO_X); | 24599 | && it->line_wrap == TRUNCATE |
| 24600 | && window_hscroll_limited (it->w, it->f) > large_hscroll_threshold) | ||
| 24601 | { | ||
| 24602 | /* Special optimization for very long and truncated lines | ||
| 24603 | which are hscrolled far to the left: jump directly to the | ||
| 24604 | (approximate) position that is visible, instead of slowly | ||
| 24605 | walking there. */ | ||
| 24606 | ptrdiff_t chars_to_skip = | ||
| 24607 | it->first_visible_x / FRAME_COLUMN_WIDTH (it->f); | ||
| 24608 | move_result = fast_move_it_horizontally (it, chars_to_skip); | ||
| 24609 | |||
| 24610 | if (move_result == MOVE_X_REACHED) | ||
| 24611 | it->current_x = it->first_visible_x; | ||
| 24612 | else /* use arbitrary value < first_visible_x */ | ||
| 24613 | it->current_x = it->first_visible_x - FRAME_COLUMN_WIDTH (it->f); | ||
| 24614 | } | ||
| 24615 | else | ||
| 24616 | move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x, | ||
| 24617 | MOVE_TO_POS | MOVE_TO_X); | ||
| 24501 | /* If we are under a large hscroll, move_it_in_display_line_to | 24618 | /* If we are under a large hscroll, move_it_in_display_line_to |
| 24502 | could hit the end of the line without reaching | 24619 | could hit the end of the line without reaching |
| 24503 | first_visible_x. Pretend that we did reach it. This is | 24620 | 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, | |||
| 27758 | even crash emacs.) */ | 27875 | even crash emacs.) */ |
| 27759 | if (mode_line_target == MODE_LINE_TITLE) | 27876 | if (mode_line_target == MODE_LINE_TITLE) |
| 27760 | return ""; | 27877 | return ""; |
| 27761 | else if (b->long_line_optimizations_p) | ||
| 27762 | { | ||
| 27763 | char *p = decode_mode_spec_buf; | ||
| 27764 | int pad = width - 2; | ||
| 27765 | while (pad-- > 0) | ||
| 27766 | *p++ = ' '; | ||
| 27767 | *p++ = '?'; | ||
| 27768 | *p++ = '?'; | ||
| 27769 | *p = '\0'; | ||
| 27770 | return decode_mode_spec_buf; | ||
| 27771 | } | ||
| 27772 | else | 27878 | else |
| 27773 | { | 27879 | { |
| 27774 | ptrdiff_t col = current_column (); | 27880 | ptrdiff_t col = current_column (); |
| @@ -36112,6 +36218,7 @@ be let-bound around code that needs to disable messages temporarily. */); | |||
| 36112 | defsubr (&Sbidi_find_overridden_directionality); | 36218 | defsubr (&Sbidi_find_overridden_directionality); |
| 36113 | defsubr (&Sdisplay__line_is_continued_p); | 36219 | defsubr (&Sdisplay__line_is_continued_p); |
| 36114 | defsubr (&Sget_display_property); | 36220 | defsubr (&Sget_display_property); |
| 36221 | defsubr (&Slong_line_optimizations_p); | ||
| 36115 | 36222 | ||
| 36116 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); | 36223 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); |
| 36117 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); | 36224 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); |