aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2022-07-27 20:05:44 +0300
committerEli Zaretskii2022-07-27 20:05:44 +0300
commita25cd7f68aa5babb7cc9002d89ff02077937927b (patch)
tree6254aab50116675fb234f66c36a6efb180c2a41d /src
parentcd41ce8c6c107901a499bf55dd2b0383befd37af (diff)
downloademacs-a25cd7f68aa5babb7cc9002d89ff02077937927b.tar.gz
emacs-a25cd7f68aa5babb7cc9002d89ff02077937927b.zip
Speed up Isearch in very long lines under line truncation
* src/xdisp.c (strings_with_newlines): New function. (forward_to_next_line_start): Call 'strings_with_newlines' in buffers with very long lines, to avoid falling back on slow iteration. (Bug#56682)
Diffstat (limited to 'src')
-rw-r--r--src/xdisp.c156
1 files changed, 144 insertions, 12 deletions
diff --git a/src/xdisp.c b/src/xdisp.c
index bd3beef134f..db3a780fcff 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -7084,6 +7084,109 @@ back_to_previous_line_start (struct it *it)
7084 get_closer_narrowed_begv (it->w, IT_CHARPOS (*it))); 7084 get_closer_narrowed_begv (it->w, IT_CHARPOS (*it)));
7085} 7085}
7086 7086
7087/* Find in the current buffer the first display or overlay string
7088 between STARTPOS and ENDPOS that includes embedded newlines.
7089 Consider only overlays that apply to window W.
7090 Value is non-zero if such a display/overlay strong is found found. */
7091static bool
7092strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
7093{
7094 int n = 0;
7095 /* Process overlays before the overlay center. */
7096 for (struct Lisp_Overlay *ov = current_buffer->overlays_before;
7097 ov; ov = ov->next)
7098 {
7099 Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
7100 eassert (OVERLAYP (overlay));
7101
7102 n++;
7103 /* Skip this overlay if it doesn't apply to our window. */
7104 Lisp_Object window = Foverlay_get (overlay, Qwindow);
7105 if (WINDOWP (window) && XWINDOW (window) != w)
7106 continue;
7107
7108 ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
7109 ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
7110
7111 /* Due to the order of overlays in overlays_before, once we get
7112 to an overlay whose end position is before STARTPOS, all the
7113 rest also end before STARTPOS, and thus are of no concern to us. */
7114 if (oend < startpos)
7115 break;
7116
7117 /* Skip overlays that don't overlap the range. */
7118 if (!((startpos < oend && ostart < endpos)
7119 || (ostart == oend
7120 && (startpos == oend || (endpos == ZV && oend == endpos)))))
7121 continue;
7122
7123 Lisp_Object str;
7124 str = Foverlay_get (overlay, Qbefore_string);
7125 if (STRINGP (str) && SCHARS (str)
7126 && memchr (SDATA (str), '\n', SBYTES (str)))
7127 return true;
7128 str = Foverlay_get (overlay, Qafter_string);
7129 if (STRINGP (str) && SCHARS (str)
7130 && memchr (SDATA (str), '\n', SBYTES (str)))
7131 return true;
7132 }
7133
7134 /* Process overlays after the overlay center. */
7135 for (struct Lisp_Overlay *ov = current_buffer->overlays_after;
7136 ov; ov = ov->next)
7137 {
7138 Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
7139 eassert (OVERLAYP (overlay));
7140 n++;
7141
7142 /* Skip this overlay if it doesn't apply to our window. */
7143 Lisp_Object window = Foverlay_get (overlay, Qwindow);
7144 if (WINDOWP (window) && XWINDOW (window) != w)
7145 continue;
7146
7147 ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
7148 ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
7149
7150 /* Due to the order of overlays in overlays_after, once we get
7151 to an overlay whose start position is after ENDPOS, all the
7152 rest also start after ENDPOS, and thus are of no concern to us. */
7153 if (ostart > endpos)
7154 break;
7155
7156 /* Skip overlays that don't overlap the range. */
7157 if (!((startpos < oend && ostart < endpos)
7158 || (ostart == oend
7159 && (startpos == oend || (endpos == ZV && oend == endpos)))))
7160 continue;
7161
7162 Lisp_Object str;
7163 str = Foverlay_get (overlay, Qbefore_string);
7164 if (STRINGP (str) && SCHARS (str)
7165 && memchr (SDATA (str), '\n', SBYTES (str)))
7166 return true;
7167 str = Foverlay_get (overlay, Qafter_string);
7168 if (STRINGP (str) && SCHARS (str)
7169 && memchr (SDATA (str), '\n', SBYTES (str)))
7170 return true;
7171 }
7172
7173 /* Check for 'display' properties whose values include strings. */
7174 Lisp_Object cpos = make_fixnum (startpos);
7175 Lisp_Object limpos = make_fixnum (endpos);
7176
7177 while ((cpos = Fnext_single_property_change (cpos, Qdisplay, Qnil, limpos),
7178 !(NILP (cpos) || XFIXNAT (cpos) >= endpos)))
7179 {
7180 Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
7181 Lisp_Object string = string_from_display_spec (spec);
7182 if (STRINGP (string)
7183 && memchr (SDATA (string), '\n', SBYTES (string)))
7184 return true;
7185 }
7186
7187 return false;
7188}
7189
7087 7190
7088/* Move IT to the next line start. 7191/* Move IT to the next line start.
7089 7192
@@ -7136,7 +7239,8 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
7136 it->selective = 0; 7239 it->selective = 0;
7137 7240
7138 /* Scan for a newline within MAX_NEWLINE_DISTANCE display elements 7241 /* Scan for a newline within MAX_NEWLINE_DISTANCE display elements
7139 from buffer text. */ 7242 from buffer text, or till the end of the string if iterating a
7243 string. */
7140 for (n = 0; 7244 for (n = 0;
7141 !newline_found_p && n < MAX_NEWLINE_DISTANCE; 7245 !newline_found_p && n < MAX_NEWLINE_DISTANCE;
7142 n += !STRINGP (it->string)) 7246 n += !STRINGP (it->string))
@@ -7156,27 +7260,54 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
7156 ptrdiff_t bytepos, start = IT_CHARPOS (*it); 7260 ptrdiff_t bytepos, start = IT_CHARPOS (*it);
7157 ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it), 7261 ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it),
7158 1, &bytepos); 7262 1, &bytepos);
7159 Lisp_Object pos;
7160
7161 eassert (!STRINGP (it->string)); 7263 eassert (!STRINGP (it->string));
7162 7264
7163 /* If there isn't any `display' property in sight, and no 7265 /* it->stop_charpos >= limit means we already know there's no
7164 overlays, we can just use the position of the newline in 7266 stop position up until the newline at LIMIT, so there's no
7165 buffer text. */ 7267 need for any further checks. */
7166 if (it->stop_charpos >= limit 7268 bool no_strings_with_newlines = it->stop_charpos >= limit;
7167 || ((pos = Fnext_single_property_change (make_fixnum (start), 7269
7168 Qdisplay, Qnil, 7270 if (!no_strings_with_newlines)
7169 make_fixnum (limit)), 7271 {
7170 (NILP (pos) || XFIXNAT (pos) == limit)) 7272 if (!current_buffer->long_line_optimizations_p)
7171 && next_overlay_change (start) == ZV)) 7273 {
7274 /* Quick-and-dirty check: if there isn't any `display'
7275 property in sight, and no overlays, we're done. */
7276 Lisp_Object pos =
7277 Fnext_single_property_change (make_fixnum (start),
7278 Qdisplay, Qnil,
7279 make_fixnum (limit));
7280 no_strings_with_newlines =
7281 (NILP (pos) || XFIXNAT (pos) == limit) /* no 'display' props */
7282 && next_overlay_change (start) == ZV; /* no overlays */
7283 }
7284 else
7285 {
7286 /* For buffers with very long lines we try harder,
7287 because it's worth our while to spend some time
7288 looking into the overlays and 'display' properties
7289 to try to avoid iterating through all of them. */
7290 no_strings_with_newlines =
7291 !strings_with_newlines (start, limit, it->w);
7292 }
7293 }
7294
7295 /* If there's no display or overlay strings with embedded
7296 newlines until the position of the newline in buffer text, we
7297 can just use that position. */
7298 if (no_strings_with_newlines)
7172 { 7299 {
7173 if (!it->bidi_p || !bidi_it_prev) 7300 if (!it->bidi_p || !bidi_it_prev)
7174 { 7301 {
7302 /* The optimal case: just jump there. */
7175 IT_CHARPOS (*it) = limit; 7303 IT_CHARPOS (*it) = limit;
7176 IT_BYTEPOS (*it) = bytepos; 7304 IT_BYTEPOS (*it) = bytepos;
7177 } 7305 }
7178 else 7306 else
7179 { 7307 {
7308 /* The less optimal case: need to bidi-walk there, but
7309 this is still cheaper that the full iteration using
7310 get_next_display_element and set_iterator_to_next. */
7180 struct bidi_it bprev; 7311 struct bidi_it bprev;
7181 7312
7182 /* Help bidi.c avoid expensive searches for display 7313 /* Help bidi.c avoid expensive searches for display
@@ -7200,6 +7331,7 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
7200 } 7331 }
7201 else 7332 else
7202 { 7333 {
7334 /* The slow case. */
7203 while (!newline_found_p) 7335 while (!newline_found_p)
7204 { 7336 {
7205 if (!get_next_display_element (it)) 7337 if (!get_next_display_element (it))