summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/display.texi6
-rw-r--r--doc/lispref/positions.texi11
-rw-r--r--etc/NEWS27
-rw-r--r--src/bytecode.c2
-rw-r--r--src/dispextern.h8
-rw-r--r--src/editfns.c75
-rw-r--r--src/indent.c5
-rw-r--r--src/lread.c2
-rw-r--r--src/process.c2
-rw-r--r--src/xdisp.c256
10 files changed, 339 insertions, 55 deletions
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 86f490677d1..d2e075c54ec 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -3480,6 +3480,12 @@ function finishes are the ones that really matter.
For efficiency, we recommend writing these functions so that they
usually assign faces to around 400 to 600 characters at each call.
+
+When the buffer text includes very long lines, these functions are
+called with the buffer narrowed to a relatively small region around
+@var{pos}, and with narrowing locked, so the functions cannot use
+@code{widen} to gain access to the rest of the buffer.
+@xref{Narrowing}.
@end defvar
@node Basic Faces
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index ca1166caac4..3a9a152f8dd 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -995,13 +995,18 @@ the entire buffer regardless of any narrowing.
types of text, consider using an alternative facility described in
@ref{Swapping Text}.
-@deffn Command narrow-to-region start end
+@deffn Command narrow-to-region start end &optional lock
This function sets the accessible portion of the current buffer to start
at @var{start} and end at @var{end}. Both arguments should be character
positions.
In an interactive call, @var{start} and @var{end} are set to the bounds
of the current region (point and the mark, with the smallest first).
+
+When @var{lock} is non-@code{nil}, calls to @code{widen}, or to
+@code{narrow-to-region} with an optional argument @var{lock}
+@code{nil}, do not produce any effect until the end of the current
+body form.
@end deffn
@deffn Command narrow-to-page &optional move-count
@@ -1027,6 +1032,10 @@ It is equivalent to the following expression:
@end example
@end deffn
+However, when @code{widen} is called inside a body form in which
+@code{narrow-to-region} was called with an optional argument
+@code{lock} non-@code{nil}, it does not produce any effect.
+
@defun buffer-narrowed-p
This function returns non-@code{nil} if the buffer is narrowed, and
@code{nil} otherwise.
diff --git a/etc/NEWS b/etc/NEWS
index b6d22fdf2b5..43f057a407b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -357,14 +357,20 @@ option) and can be set to nil to disable Just-in-time Lock mode.
---
** Emacs is now capable of editing files with arbitrarily long lines.
The display of long lines has been optimized, and Emacs no longer
-chokes when a buffer on display contains long lines. If you still
-experience slowdowns while editing files with long lines, this is
-either due to font locking, which you can turn off with 'M-x
-font-lock-mode' or 'C-u C-x x f', or to the current major mode or one
-of the enabled minor modes, in which case you should open the the file
-with 'M-x find-file-literally' instead of 'C-x C-f'. The variable
+chokes when a buffer on display contains long lines. The variable
'long-line-threshold' controls whether and when these display
-optimizations are used.
+optimizations are in effect.
+
+If you still experience slowdowns while editing files with long lines,
+this is due to line truncation, or to one of the enabled minor modes,
+or to the current major mode. Try turning off line truncation with
+'C-x x t', or try disabling all known slow minor modes with 'M-x
+so-long-minor-mode', or try disabling all known slow minor modes and
+the major mode with 'M-x so-long-mode', or visit the file with 'M-x
+find-file-literally' instead of the usual 'C-x C-f'.
+
+Note that the display optimizations in these cases may cause the
+buffer to be occasionally mis-fontified.
+++
** New command to change the font size globally.
@@ -2520,6 +2526,13 @@ things to be saved.
** New function 'string-equal-ignore-case'.
This compares strings ignoring case differences.
++++
+** New argument LOCK of 'narrow-to-region'.
+If 'narrow-to-region' is called from Lisp with the new optional
+argument LOCK non-nil, then calls to 'widen' and calls to
+'narrow-to-region' with the optional argument LOCK nil or omitted do
+not produce any effect until the end of the current body form.
+
** Themes
---
diff --git a/src/bytecode.c b/src/bytecode.c
index d75767bb0c5..241cbaf04f6 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1481,7 +1481,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
CASE (Bnarrow_to_region):
{
Lisp_Object v1 = POP;
- TOP = Fnarrow_to_region (TOP, v1);
+ TOP = Fnarrow_to_region (TOP, v1, Qnil);
NEXT;
}
diff --git a/src/dispextern.h b/src/dispextern.h
index 1cdfdca74c0..2772e8cda8d 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2336,6 +2336,10 @@ struct it
optimize display (see the SET_WITH_NARROWED_BEGV macro). */
ptrdiff_t narrowed_begv;
+ /* Alternate end position of the buffer that may be used to
+ optimize display. */
+ ptrdiff_t narrowed_zv;
+
/* C string to iterate over. Non-null means get characters from
this string, otherwise characters are read from current_buffer
or it->string. */
@@ -3400,7 +3404,9 @@ void mark_window_display_accurate (Lisp_Object, bool);
void redisplay_preserve_echo_area (int);
void init_iterator (struct it *, struct window *, ptrdiff_t,
ptrdiff_t, struct glyph_row *, enum face_id);
-ptrdiff_t get_narrowed_begv (struct window *w);
+ptrdiff_t get_narrowed_begv (struct window *);
+ptrdiff_t get_narrowed_zv (struct window *);
+ptrdiff_t get_closer_narrowed_begv (struct window *, ptrdiff_t);
void init_iterator_to_row_start (struct it *, struct window *,
struct glyph_row *);
void start_display (struct it *, struct window *, struct text_pos);
diff --git a/src/editfns.c b/src/editfns.c
index 4587b1132b1..d15d4dc68b9 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2658,9 +2658,15 @@ DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
doc: /* Remove restrictions (narrowing) from current buffer.
-This allows the buffer's full text to be seen and edited. */)
+This allows the buffer's full text to be seen and edited.
+
+When called from Lisp inside a body form in which `narrow-to-region'
+was called with an optional argument LOCK non-nil, this function does
+not produce any effect. */)
(void)
{
+ if (! NILP (Vrestrictions_locked))
+ return Qnil;
if (BEG != BEGV || Z != ZV)
current_buffer->clip_changed = 1;
BEGV = BEG;
@@ -2671,7 +2677,19 @@ This allows the buffer's full text to be seen and edited. */)
return Qnil;
}
-DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
+static void
+unwind_locked_begv (Lisp_Object point_min)
+{
+ SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
+
+static void
+unwind_locked_zv (Lisp_Object point_max)
+{
+ SET_BUF_ZV (current_buffer, XFIXNUM (point_max));
+}
+
+DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 3, "r",
doc: /* Restrict editing in this buffer to the current region.
The rest of the text becomes temporarily invisible and untouchable
but is not deleted; if you save the buffer in a file, the invisible
@@ -2680,8 +2698,13 @@ See also `save-restriction'.
When calling from Lisp, pass two arguments START and END:
positions (integers or markers) bounding the text that should
-remain visible. */)
- (Lisp_Object start, Lisp_Object end)
+remain visible.
+
+When called from Lisp with the optional argument LOCK non-nil,
+calls to `widen', or to `narrow-to-region' with an optional
+argument LOCK nil, do not produce any effect until the end of
+the current body form. */)
+ (Lisp_Object start, Lisp_Object end, Lisp_Object lock)
{
EMACS_INT s = fix_position (start), e = fix_position (end);
@@ -2690,14 +2713,37 @@ remain visible. */)
EMACS_INT tem = s; s = e; e = tem;
}
- if (!(BEG <= s && s <= e && e <= Z))
- args_out_of_range (start, end);
+ if (! NILP (lock))
+ {
+ if (!(BEGV <= s && s <= e && e <= ZV))
+ args_out_of_range (start, end);
- if (BEGV != s || ZV != e)
- current_buffer->clip_changed = 1;
+ if (BEGV != s || ZV != e)
+ current_buffer->clip_changed = 1;
+
+ record_unwind_protect (unwind_locked_begv, Fpoint_min ());
+ record_unwind_protect (unwind_locked_zv, Fpoint_max ());
+
+ SET_BUF_BEGV (current_buffer, s);
+ SET_BUF_ZV (current_buffer, e);
+
+ specbind (Qrestrictions_locked, Qt);
+ }
+ else
+ {
+ if (! NILP (Vrestrictions_locked))
+ return Qnil;
+
+ if (!(BEG <= s && s <= e && e <= Z))
+ args_out_of_range (start, end);
+
+ if (BEGV != s || ZV != e)
+ current_buffer->clip_changed = 1;
+
+ SET_BUF_BEGV (current_buffer, s);
+ SET_BUF_ZV (current_buffer, e);
+ }
- SET_BUF_BEGV (current_buffer, s);
- SET_BUF_ZV (current_buffer, e);
if (PT < s)
SET_PT (s);
if (e < PT)
@@ -4517,6 +4563,15 @@ This variable is experimental; email 32252@debbugs.gnu.org if you need
it to be non-nil. */);
binary_as_unsigned = false;
+ DEFSYM (Qrestrictions_locked, "restrictions-locked");
+ DEFVAR_LISP ("restrictions-locked", Vrestrictions_locked,
+ doc: /* If non-nil, restrictions are currently locked.
+
+This happens when `narrow-to-region', which see, is called from Lisp
+with an optional argument LOCK non-nil. */);
+ Vrestrictions_locked = Qnil;
+ Funintern (Qrestrictions_locked, Qnil);
+
defsubr (&Spropertize);
defsubr (&Schar_equal);
defsubr (&Sgoto_char);
diff --git a/src/indent.c b/src/indent.c
index d4ef075f001..e90e3fde203 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -306,6 +306,8 @@ and point (e.g., control characters will have a width of 2 or 4, tabs
will have a variable width).
Ignores finite width of frame, which means that this function may return
values greater than (frame-width).
+In a buffer with very long lines, the value can be zero, because calculating
+the exact number is very expensive.
Whether the line is visible (if `selective-display' is t) has no effect;
however, ^M is treated as end of line when `selective-display' is t.
Text that has an invisible property is considered as having width 0, unless
@@ -313,6 +315,9 @@ Text that has an invisible property is considered as having width 0, unless
(void)
{
Lisp_Object temp;
+
+ if (current_buffer->long_line_optimizations_p)
+ return make_fixnum (0);
XSETFASTINT (temp, current_column ());
return temp;
}
diff --git a/src/lread.c b/src/lread.c
index 0b46a2e4ee5..0720774db2b 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2261,7 +2261,7 @@ readevalloop (Lisp_Object readcharfun,
/* Set point and ZV around stuff to be read. */
Fgoto_char (start);
if (!NILP (end))
- Fnarrow_to_region (make_fixnum (BEGV), end);
+ Fnarrow_to_region (make_fixnum (BEGV), end, Qnil);
/* Just for cleanliness, convert END to a marker
if it is an integer. */
diff --git a/src/process.c b/src/process.c
index 1ac5a509e56..a15efa39bd1 100644
--- a/src/process.c
+++ b/src/process.c
@@ -6339,7 +6339,7 @@ Otherwise it discards the output. */)
/* If the restriction isn't what it should be, set it. */
if (old_begv != BEGV || old_zv != ZV)
- Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv));
+ Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv), Qnil);
bset_read_only (current_buffer, old_read_only);
SET_PT_BOTH (opoint, opoint_byte);
diff --git a/src/xdisp.c b/src/xdisp.c
index e998df32a6a..2c889586cd6 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3426,7 +3426,10 @@ init_iterator (struct it *it, struct window *w,
}
if (current_buffer->long_line_optimizations_p)
- it->narrowed_begv = get_narrowed_begv (w);
+ {
+ it->narrowed_begv = get_narrowed_begv (w);
+ it->narrowed_zv = get_narrowed_zv (w);
+ }
/* If a buffer position was specified, set the iterator there,
getting overlays and face properties from that position. */
@@ -3494,23 +3497,50 @@ init_iterator (struct it *it, struct window *w,
CHECK_IT (it);
}
-/* Compute a suitable alternate value for BEGV that may be used
+/* Compute a suitable alternate value for BEGV and ZV 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)
+static int
+get_narrowed_width (struct window *w)
{
- int len, fact; ptrdiff_t begv;
+ int fact;
/* In a character-only terminal, only one font size is used, so we
can use a smaller factor. */
fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3;
- len = fact * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
- window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS));
+ return fact * window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+static int
+get_narrowed_len (struct window *w)
+{
+ return get_narrowed_width (w) *
+ window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+ptrdiff_t
+get_narrowed_begv (struct window *w)
+{
+ int len = get_narrowed_len (w);
+ ptrdiff_t begv;
begv = max ((window_point (w) / len - 1) * len, BEGV);
return begv == BEGV ? 0 : begv;
}
+ptrdiff_t
+get_narrowed_zv (struct window *w)
+{
+ int len = get_narrowed_len (w);
+ return min ((window_point (w) / len + 1) * len, ZV);
+}
+
+ptrdiff_t
+get_closer_narrowed_begv (struct window *w, ptrdiff_t pos)
+{
+ int len = get_narrowed_width (w);
+ return max ((pos / len - 1) * len, BEGV);
+}
+
static void
unwind_narrowed_begv (Lisp_Object point_min)
{
@@ -3518,15 +3548,15 @@ unwind_narrowed_begv (Lisp_Object point_min)
}
/* Set DST to EXPR. When IT indicates that BEGV should temporarily be
- updated to optimize display, evaluate EXPR with an updated BEGV. */
+ updated to optimize display, evaluate EXPR with BEGV set to BV. */
-#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR) \
+#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR,BV) \
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); \
+ SET_BUF_BEGV (current_buffer, BV); \
DST = EXPR; \
unbind_to (count, Qnil); \
} \
@@ -4377,6 +4407,10 @@ handle_fontified_prop (struct it *it)
eassert (it->end_charpos == ZV);
+ if (it->narrowed_begv)
+ Fnarrow_to_region (make_fixnum (it->narrowed_begv),
+ make_fixnum (it->narrowed_zv), Qt);
+
/* Don't allow Lisp that runs from 'fontification-functions'
clear our face and image caches behind our back. */
it->f->inhibit_clear_image_cache = true;
@@ -7035,7 +7069,108 @@ back_to_previous_line_start (struct it *it)
dec_both (&cp, &bp);
SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
- find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
+ find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)),
+ get_closer_narrowed_begv (it->w, IT_CHARPOS (*it)));
+}
+
+/* Find in the current buffer the first display or overlay string
+ between STARTPOS and ENDPOS that includes embedded newlines.
+ Consider only overlays that apply to window W.
+ Value is non-zero if such a display/overlay string is found. */
+static bool
+strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
+{
+ /* Process overlays before the overlay center. */
+ for (struct Lisp_Overlay *ov = current_buffer->overlays_before;
+ ov; ov = ov->next)
+ {
+ Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+ eassert (OVERLAYP (overlay));
+
+ /* Skip this overlay if it doesn't apply to our window. */
+ Lisp_Object window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+
+ ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+ ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+ /* Due to the order of overlays in overlays_before, once we get
+ to an overlay whose end position is before STARTPOS, all the
+ rest also end before STARTPOS, and thus are of no concern to us. */
+ if (oend < startpos)
+ break;
+
+ /* Skip overlays that don't overlap the range. */
+ if (!((startpos < oend && ostart < endpos)
+ || (ostart == oend
+ && (startpos == oend || (endpos == ZV && oend == endpos)))))
+ continue;
+
+ Lisp_Object str;
+ str = Foverlay_get (overlay, Qbefore_string);
+ if (STRINGP (str) && SCHARS (str)
+ && memchr (SDATA (str), '\n', SBYTES (str)))
+ return true;
+ str = Foverlay_get (overlay, Qafter_string);
+ if (STRINGP (str) && SCHARS (str)
+ && memchr (SDATA (str), '\n', SBYTES (str)))
+ return true;
+ }
+
+ /* Process overlays after the overlay center. */
+ for (struct Lisp_Overlay *ov = current_buffer->overlays_after;
+ ov; ov = ov->next)
+ {
+ Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+ eassert (OVERLAYP (overlay));
+
+ /* Skip this overlay if it doesn't apply to our window. */
+ Lisp_Object window = Foverlay_get (overlay, Qwindow);
+ if (WINDOWP (window) && XWINDOW (window) != w)
+ continue;
+
+ ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+ ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+ /* Due to the order of overlays in overlays_after, once we get
+ to an overlay whose start position is after ENDPOS, all the
+ rest also start after ENDPOS, and thus are of no concern to us. */
+ if (ostart > endpos)
+ break;
+
+ /* Skip overlays that don't overlap the range. */
+ if (!((startpos < oend && ostart < endpos)
+ || (ostart == oend
+ && (startpos == oend || (endpos == ZV && oend == endpos)))))
+ continue;
+
+ Lisp_Object str;
+ str = Foverlay_get (overlay, Qbefore_string);
+ if (STRINGP (str) && SCHARS (str)
+ && memchr (SDATA (str), '\n', SBYTES (str)))
+ return true;
+ str = Foverlay_get (overlay, Qafter_string);
+ if (STRINGP (str) && SCHARS (str)
+ && memchr (SDATA (str), '\n', SBYTES (str)))
+ return true;
+ }
+
+ /* Check for 'display' properties whose values include strings. */
+ Lisp_Object cpos = make_fixnum (startpos);
+ Lisp_Object limpos = make_fixnum (endpos);
+
+ while ((cpos = Fnext_single_property_change (cpos, Qdisplay, Qnil, limpos),
+ !(NILP (cpos) || XFIXNAT (cpos) >= endpos)))
+ {
+ Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
+ Lisp_Object string = string_from_display_spec (spec);
+ if (STRINGP (string)
+ && memchr (SDATA (string), '\n', SBYTES (string)))
+ return true;
+ }
+
+ return false;
}
@@ -7090,7 +7225,8 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
it->selective = 0;
/* Scan for a newline within MAX_NEWLINE_DISTANCE display elements
- from buffer text. */
+ from buffer text, or till the end of the string if iterating a
+ string. */
for (n = 0;
!newline_found_p && n < MAX_NEWLINE_DISTANCE;
n += !STRINGP (it->string))
@@ -7110,27 +7246,55 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
ptrdiff_t bytepos, start = IT_CHARPOS (*it);
ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it),
1, &bytepos);
- Lisp_Object pos;
-
eassert (!STRINGP (it->string));
- /* If there isn't any `display' property in sight, and no
- overlays, we can just use the position of the newline in
- buffer text. */
- if (it->stop_charpos >= limit
- || ((pos = Fnext_single_property_change (make_fixnum (start),
- Qdisplay, Qnil,
- make_fixnum (limit)),
- NILP (pos))
- && next_overlay_change (start) == ZV))
+ /* it->stop_charpos >= limit means we already know there's no
+ stop position up until the newline at LIMIT, so there's no
+ need for any further checks. */
+ bool no_strings_with_newlines = it->stop_charpos >= limit;
+
+ if (!no_strings_with_newlines)
{
- if (!it->bidi_p)
+ if (!(current_buffer->long_line_optimizations_p
+ && it->line_wrap == TRUNCATE))
+ {
+ /* Quick-and-dirty check: if there isn't any `display'
+ property in sight, and no overlays, we're done. */
+ Lisp_Object pos =
+ Fnext_single_property_change (make_fixnum (start),
+ Qdisplay, Qnil,
+ make_fixnum (limit));
+ no_strings_with_newlines =
+ (NILP (pos) || XFIXNAT (pos) == limit) /* no 'display' props */
+ && next_overlay_change (start) == ZV; /* no overlays */
+ }
+ else
+ {
+ /* For buffers with very long and truncated lines we try
+ harder, because it's worth our while to spend some
+ time looking into the overlays and 'display' properties
+ if we can then avoid iterating through all of them. */
+ no_strings_with_newlines =
+ !strings_with_newlines (start, limit, it->w);
+ }
+ }
+
+ /* If there's no display or overlay strings with embedded
+ newlines until the position of the newline in buffer text, we
+ can just use that position. */
+ if (no_strings_with_newlines)
+ {
+ if (!it->bidi_p || !bidi_it_prev)
{
+ /* The optimal case: just jump there. */
IT_CHARPOS (*it) = limit;
IT_BYTEPOS (*it) = bytepos;
}
else
{
+ /* The less optimal case: need to bidi-walk there, but
+ this is still cheaper that the full iteration using
+ get_next_display_element and set_iterator_to_next. */
struct bidi_it bprev;
/* Help bidi.c avoid expensive searches for display
@@ -7154,6 +7318,7 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
}
else
{
+ /* The slow case. */
while (!newline_found_p)
{
if (!get_next_display_element (it))
@@ -7287,7 +7452,8 @@ reseat_at_next_visible_line_start (struct it *it, bool on_newline_p)
bool skipped_p = false;
struct bidi_it bidi_it_prev;
bool newline_found_p
- = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+ = forward_to_next_line_start (it, &skipped_p,
+ on_newline_p ? &bidi_it_prev : NULL);
/* Skip over lines that are invisible because they are indented
more than the value of IT->selective. */
@@ -7299,7 +7465,8 @@ reseat_at_next_visible_line_start (struct it *it, bool on_newline_p)
eassert (IT_BYTEPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
newline_found_p =
- forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+ forward_to_next_line_start (it, &skipped_p,
+ on_newline_p ? &bidi_it_prev : NULL);
}
/* Position on the newline if that's what's requested. */
@@ -8672,7 +8839,8 @@ get_visually_first_element (struct it *it)
SET_WITH_NARROWED_BEGV (it, bob,
string_p ? 0 :
- IT_BYTEPOS (*it) < BEGV ? obegv : BEGV);
+ IT_BYTEPOS (*it) < BEGV ? obegv : BEGV,
+ it->narrowed_begv);
if (STRINGP (it->string))
{
@@ -8715,7 +8883,8 @@ get_visually_first_element (struct it *it)
SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
find_newline_no_quit (IT_CHARPOS (*it),
IT_BYTEPOS (*it), -1,
- &it->bidi_it.bytepos));
+ &it->bidi_it.bytepos),
+ it->narrowed_begv);
bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
do
{
@@ -10634,7 +10803,8 @@ move_it_vertically_backward (struct it *it, int dy)
dec_both (&cp, &bp);
SET_WITH_NARROWED_BEGV (it, cp,
- find_newline_no_quit (cp, bp, -1, NULL));
+ find_newline_no_quit (cp, bp, -1, NULL),
+ it->narrowed_begv);
move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
}
bidi_unshelve_cache (it3data, true);
@@ -12964,7 +13134,8 @@ mode_line_update_needed (struct window *w)
{
return (w->column_number_displayed != -1
&& !(PT == w->last_point && !window_outdated (w))
- && (w->column_number_displayed != current_column ()));
+ && (!current_buffer->long_line_optimizations_p
+ && w->column_number_displayed != current_column ()));
}
/* True if window start of W is frozen and may not be changed during
@@ -18936,8 +19107,9 @@ set_vertical_scroll_bar (struct window *w)
end = BUF_Z (buf) - w->window_end_pos - BUF_BEGV (buf);
/* If w->window_end_pos cannot be trusted, recompute it "the
- hard way". */
- if (!MINI_WINDOW_P (w))
+ hard way". But don't bother to be too accurate when
+ long-line shortcuts are in effect. */
+ if (!w->window_end_valid && !buf->long_line_optimizations_p)
{
struct it it;
struct text_pos start_pos;
@@ -20086,6 +20258,7 @@ 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)
@@ -27587,6 +27760,17 @@ 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 ();
@@ -36473,7 +36657,13 @@ The tool bar style must also show labels for this to have any effect, see
doc: /* List of functions to call to fontify regions of text.
Each function is called with one argument POS. Functions must
fontify a region starting at POS in the current buffer, and give
-fontified regions the property `fontified'. */);
+fontified regions the property `fontified' with a non-nil value.
+
+Note that, when the buffer contains one or more lines whose length is
+above `long-line-threshold', these functions only have access to a
+small portion of the buffer around POS, and cannot use `widen' to gain
+access to other portions of buffer text because the narrowing of the
+buffer is locked (see `narrow-to-region'). */);
Vfontification_functions = Qnil;
Fmake_variable_buffer_local (Qfontification_functions);