summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGregory Heytings <gregory@heytings.org>2022-07-16 19:06:38 +0000
committerGregory Heytings <gregory@heytings.org>2022-07-16 21:13:33 +0200
commite7b5912b235936b304701ba6b1e808d9b197fd4f (patch)
tree78cfbd3ab9c032e45a6ba0f1e763807a01a9a3ec /src
parent9de00e5fda2e04316357bd8cf0d8094c63ff171b (diff)
downloademacs-e7b5912b235936b304701ba6b1e808d9b197fd4f.tar.gz
Improvements to long lines handling.
* src/buffer.h (struct buffer): New field 'long_line_optimizations_p'. * src/buffer.c (syms_of_buffer): New variable 'long-line-threshold'. (reset_buffer): Initialize the 'long_line_optimizations_p' field. (Fbuffer_swap_text): Handle it. * src/xdisp.c (redisplay_window): Set 'long_line_optimizations_p' when a buffer contains long lines. (init_iterator): Use 'long_line_optimizations_p'. (get_narrowed_begv): Update. (SET_WITH_NARROWED_BEGV): New macro. (unwind_narrowed_begv): New internal function used by the new macro. (back_to_previous_line_start, get_visually_first_element, move_it_vertically_backward): Use the new macro. * src/search.c (find_newline1): Make it externally visible. * src/lisp.h: Make 'find_newline1' externally visible. * src/dispextern.h (struct it): Update comment. Remove the 'WITH_NARROWED_BEGV' macro. * etc/NEWS: Mention the 'long-line-threshold' variable.
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c10
-rw-r--r--src/buffer.h4
-rw-r--r--src/dispextern.h16
-rw-r--r--src/lisp.h2
-rw-r--r--src/search.c2
-rw-r--r--src/xdisp.c72
6 files changed, 76 insertions, 30 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 509ce51b55e..a777668e44b 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -984,6 +984,7 @@ reset_buffer (register struct buffer *b)
/* It is more conservative to start out "changed" than "unchanged". */
b->clip_changed = 0;
b->prevent_redisplay_optimizations_p = 1;
+ b->long_line_optimizations_p = 0;
bset_backed_up (b, Qnil);
bset_local_minor_modes (b, Qnil);
BUF_AUTOSAVE_MODIFF (b) = 0;
@@ -2445,6 +2446,7 @@ results, see Info node `(elisp)Swapping Text'. */)
swapfield (bidi_paragraph_cache, struct region_cache *);
current_buffer->prevent_redisplay_optimizations_p = 1;
other_buffer->prevent_redisplay_optimizations_p = 1;
+ swapfield (long_line_optimizations_p, bool_bf);
swapfield (overlays_before, struct Lisp_Overlay *);
swapfield (overlays_after, struct Lisp_Overlay *);
swapfield (overlay_center, ptrdiff_t);
@@ -6423,6 +6425,14 @@ Since `clone-indirect-buffer' calls `make-indirect-buffer', this hook
will run for `clone-indirect-buffer' calls as well. */);
Vclone_indirect_buffer_hook = Qnil;
+ DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold,
+ doc: /* Line length above which specific display optimizations are used.
+Display optimizations for long lines will automatically be enabled in
+buffers which contain one or more lines whose length is above that
+threshold.
+When nil, these display optimizations are disabled. */);
+ XSETFASTINT (Vlong_line_threshold, 10000);
+
defsubr (&Sbuffer_live_p);
defsubr (&Sbuffer_list);
defsubr (&Sget_buffer);
diff --git a/src/buffer.h b/src/buffer.h
index 135eaf72d30..09daa29992a 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -681,6 +681,10 @@ struct buffer
defined, as well as by with-temp-buffer, for example. */
bool_bf inhibit_buffer_hooks : 1;
+ /* Non-zero when the buffer contains long lines and specific
+ display optimizations must be used. */
+ bool_bf long_line_optimizations_p : 1;
+
/* List of overlays that end at or before the current center,
in order of end-position. */
struct Lisp_Overlay *overlays_before;
diff --git a/src/dispextern.h b/src/dispextern.h
index 2edf4b73f81..c5794994950 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2332,8 +2332,8 @@ struct it
with which display_string was called. */
ptrdiff_t end_charpos;
- /* Alternate begin position of the buffer, which is used to optimize
- display (see the WITH_NARROWED_BEGV macro below). */
+ /* Alternate begin position of the buffer that may be used to
+ optimize display (see the WITH_NARROWED_BEGV macro below). */
ptrdiff_t narrowed_begv;
/* C string to iterate over. Non-null means get characters from
@@ -2817,18 +2817,6 @@ struct it
reset_box_start_end_flags ((IT)); \
} while (false)
-/* Execute STATEMENT with a temporarily narrowed buffer. */
-
-#define WITH_NARROWED_BEGV(STATEMENT) \
- do { \
- ptrdiff_t obegv = BEGV; \
- if (it->narrowed_begv) \
- SET_BUF_BEGV (current_buffer, it->narrowed_begv); \
- STATEMENT; \
- if (it->narrowed_begv) \
- SET_BUF_BEGV (current_buffer, obegv); \
- } while (0)
-
/* Bit-flags indicating what operation move_it_to should perform. */
enum move_operation_enum
diff --git a/src/lisp.h b/src/lisp.h
index e4a49b8ef94..5045d49e1b6 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4761,6 +4761,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case (Lisp_Object, const char *,
ptrdiff_t);
extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t, Lisp_Object);
+extern ptrdiff_t find_newline1 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
+ ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
diff --git a/src/search.c b/src/search.c
index 9d6bd074e1b..b5d6a442c0f 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3192,7 +3192,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0,
}
/* Like find_newline, but doesn't use the cache, and only searches forward. */
-static ptrdiff_t
+ptrdiff_t
find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
ptrdiff_t *bytepos, bool allow_quit)
diff --git a/src/xdisp.c b/src/xdisp.c
index ac76917eb3f..98bf15a8594 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3425,7 +3425,8 @@ init_iterator (struct it *it, struct window *w,
}
}
- it->narrowed_begv = get_narrowed_begv (w);
+ if (current_buffer->long_line_optimizations_p)
+ it->narrowed_begv = get_narrowed_begv (w);
/* If a buffer position was specified, set the iterator there,
getting overlays and face properties from that position. */
@@ -3493,20 +3494,43 @@ init_iterator (struct it *it, struct window *w,
CHECK_IT (it);
}
-/* Compute a suitable value for BEGV that can be used temporarily, to
- optimize display, for the buffer in window W. */
+/* Compute a suitable alternate value for BEGV that may be used
+ temporarily to optimize display if the buffer in window W contains
+ long lines. */
ptrdiff_t
get_narrowed_begv (struct window *w)
{
int len; ptrdiff_t begv;
- len = (1 + ((window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
- window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)) /
- 10000)) * 10000;
- begv = max ((PT / len - 2) * len, BEGV);
+ len = 3 * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
+ window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS));
+ begv = max ((window_point (w) / len - 1) * len, BEGV);
return begv == BEGV ? 0 : begv;
}
+static void
+unwind_narrowed_begv (Lisp_Object point_min)
+{
+ SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
+
+/* Set DST to EXPR. When IT indicates that BEGV should temporarily be
+ updated to optimize display, evaluate EXPR with an updated BEGV. */
+
+#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR) \
+ do { \
+ if (IT->narrowed_begv) \
+ { \
+ specpdl_ref count = SPECPDL_INDEX (); \
+ record_unwind_protect (unwind_narrowed_begv, Fpoint_min ()); \
+ SET_BUF_BEGV (current_buffer, IT->narrowed_begv); \
+ DST = EXPR; \
+ unbind_to (count, Qnil); \
+ } \
+ else \
+ DST = EXPR; \
+ } while (0)
+
/* Initialize IT for the display of window W with window start POS. */
void
@@ -7007,8 +7031,8 @@ back_to_previous_line_start (struct it *it)
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
dec_both (&cp, &bp);
- WITH_NARROWED_BEGV (IT_CHARPOS (*it) =
- find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
+ SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
+ find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
}
@@ -8642,7 +8666,7 @@ get_visually_first_element (struct it *it)
ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV);
ptrdiff_t bob;
- WITH_NARROWED_BEGV (bob = (string_p ? 0 : BEGV));
+ SET_WITH_NARROWED_BEGV (it, bob, string_p ? 0 : BEGV);
if (STRINGP (it->string))
{
@@ -8682,10 +8706,10 @@ get_visually_first_element (struct it *it)
if (string_p)
it->bidi_it.charpos = it->bidi_it.bytepos = 0;
else
- WITH_NARROWED_BEGV (it->bidi_it.charpos =
- find_newline_no_quit (IT_CHARPOS (*it),
- IT_BYTEPOS (*it), -1,
- &it->bidi_it.bytepos));
+ SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
+ find_newline_no_quit (IT_CHARPOS (*it),
+ IT_BYTEPOS (*it), -1,
+ &it->bidi_it.bytepos));
bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
do
{
@@ -10603,7 +10627,8 @@ move_it_vertically_backward (struct it *it, int dy)
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
dec_both (&cp, &bp);
- WITH_NARROWED_BEGV (cp = find_newline_no_quit (cp, bp, -1, NULL));
+ SET_WITH_NARROWED_BEGV (it, cp,
+ find_newline_no_quit (cp, bp, -1, NULL));
move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
}
bidi_unshelve_cache (it3data, true);
@@ -19245,6 +19270,23 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
}
}
+ /* Check whether the buffer to be displayed contains long lines. */
+ if (!NILP (Vlong_line_threshold)
+ && !current_buffer->long_line_optimizations_p
+ && MODIFF != UNCHANGED_MODIFIED)
+ {
+ ptrdiff_t cur, next, found, max = 0;
+ for (cur = 1; cur < Z; cur = next)
+ {
+ next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1,
+ &found, NULL, true);
+ if (next - cur > max) max = next - cur;
+ if (!found || max > XFIXNUM (Vlong_line_threshold)) break;
+ }
+ if (max > XFIXNUM (Vlong_line_threshold))
+ current_buffer->long_line_optimizations_p = true;
+ }
+
/* If window-start is screwed up, choose a new one. */
if (XMARKER (w->start)->buffer != current_buffer)
goto recenter;